delphi - 有效地将 delphi/freepascal 集合复制到网格

标签 delphi collections grid rtti

我正在尝试找到从 Delphi/Lazarus FreePascal 集合更新网格(StringGrid 或 KGrid)的最有效方法。

我的收藏之一如下:

{ TEntretien }
TEntretien = class(TCollectionItem)
private
  { private declarations }
  FPrenom: string;
  FSexe: string;
  FSigneDistinctif: string;
  FPays: string;
  FTotale: integer;
  FColumns: integer;
public
  { public declarations }
published
  { published declarations }
  property Prenom: string read FPrenom write FPrenom;
  property Sexe: string read FSexe write FSexe;
  property SigneDistinctif: string read FSigneDistinctif write FSigneDistinctif;
  property Pays: string read FPays write FPays;
property Totale: integer read FTotale write FTotale;
end;

{ TEntretiens }
TEntretiens = class(TCollection)
private
  { private declarations }
  function GetItem(AIndex: integer): TEntretien;
public
  { public declarations }
  constructor Create;
  function Add: TEntretien;
  property Items[AIndex: integer]: TEntretien read GetItem; default;
end;

我有以下代码片段,用于更新我的一个网格:

// Fill the grid with the results of the query
for intGridRow := 0 to intNumberOfRows - 1 do
begin
  for intGridCol := 0 to intNumberOfColumns - 1 do
  begin
    // Write the rest of the retrieved data into the grid proper   USE RTTI HERE??
    if intGridCol = 0 then
      kgGridName.Cells[intGridCol + kgGridName.FixedCols, intGridRow + kgGridName.FixedRows] := 
         AEntretiens[intGridRow].Prenom
    else if intGridCol = 1 then
       kgGridName.Cells[intGridCol + kgGridName.FixedCols, intGridRow + kgGridName.FixedRows] :=
         AEntretiens[intGridRow].Sexe
    else if intGridCol = 2 then
       kgGridName.Cells[intGridCol + kgGridName.FixedCols, intGridRow + kgGridName.FixedRows] :=
         AEntretiens[intGridRow].SigneDistinctif
    else if intGridCol = 3 then
       kgGridName.Cells[intGridCol + kgGridName.FixedCols, intGridRow + kgGridName.FixedRows] :=
         AEntretiens[intGridRow].Pays
    else if intGridCol = 4 then
       kgGridName.Cells[intGridCol + kgGridName.FixedCols, intGridRow + kgGridName.FixedRows] := IntToStr(AEntretiens[intGridRow].Totale)
    end;
end;

这对于具有少量字段/属性的集合来说很好,但我也有最多 40 个字段的集合,所以我上面使用的方法太麻烦了。

有没有更有效的方法来做到这一点?有人建议使用RTTI,但我不知道如何使用它。

非常感谢,

丹尼尔

最佳答案

这是一个 Delphi 增强型 RTTI 实现。这从 Delphi-2010 开始有效。

它将搜索所有可读的已发布属性(按声明的顺序)并用值填充网格。

如果您有多个整数和字符串作为属性,请在 case 语句中添加更多内容。

uses
  System.Classes,System.RTTI,System.TypInfo, System.SysUtils;

procedure Test;
// Fill the grid with the results of the query
Var
  AnItem     : TEntretien;
  fixedCols  : integer;
  fixedRows  : integer;
  ARow,ACol  : integer;
  intGridRow : integer;
  context    : TRttiContext;
  rType      : TRttiType;
  prop       : TRttiProperty;
  value      : TValue;
  s          : String;
begin
  context := TRttiContext.Create;
  rType := context.GetType(TEntretien);
  fixedCols := kgGridName.FixedCols;
  fixedRows := kgGridName.FixedRows;
  for intGridRow := 0 to intNumberOfRows - 1 do
  begin
    AnItem := AEntretiens[intGridRow];
    ARow := intGridRow + fixedRows;
    ACol := fixedCols;
    for prop in rType.GetProperties do
    begin
      if prop.IsReadable then
      begin
        s := '';
        value := prop.GetValue(AnItem);
        case prop.PropertyType.TypeKind of
          tkInteger : s := IntToStr(value.AsInteger);
          tkString : s := value.AsString;
        end;
        kgGridName.Cells[ACol, ARow] := s;
        Inc(ACol);
      end;
    end;
  end;
end;

正如 Ken 在评论中提到的,Lazarus/FreePascal 中未实现增强型 RTTI。

适用于所有平台的通用解决方案是添加一个集合项基类,并可以获取属性值。

Type
  TBaseItemClass = class(TCollectionItem)
    private
      function GetPropertyCount : integer; virtual; abstract;  
      function GetPropertyString( index : integer) : string; virtual; abstract;
    public
      property PropertyCount : integer read GetPropertyCount;
      property PropertyString[index : integer] : string read GetPropertyString;
  end;

那么你的声明和实现将如下所示:

{ TEntretien }
TEntretien = class(TBaseItemClass)
private
  { private declarations }
  FPrenom: string;
  FSexe: string;
  FSigneDistinctif: string;
  FPays: string;
  FTotale: integer;
  FColumns: integer;
  function GetPropertyCount : integer; override;
  function GetPropertyString( index : integer) : string; override;
public
  { public declarations }
published
  { published declarations }
  property Prenom: string read FPrenom write FPrenom;
  property Sexe: string read FSexe write FSexe;
  property SigneDistinctif: string read FSigneDistinctif write FSigneDistinctif;
  property Pays: string read FPays write FPays;
  property Totale: integer read FTotale write FTotale;
end;

function TEntretien.GetPropertyCount : integer;
begin
  Result := 5;
end;

function TEntretien.GetPropertyString(index : integer) : string;
begin
  Result := '';
  case index of
    0 : Result := Prenom;
    1 : Result := Sexe;
    2 : Result := SigneDistinctif;
    3 : Result := Pays;
    4 : Result := IntToStr(Totale);
  end;
end;

procedure Test1;
// Fill the grid with the results of the query
Var
  AnItem    : TEntretien;
  intGridRow,intNumberOfRows : Integer;
  fixedCols : integer;
  fixedRows : integer;
  ARow      : integer;
  i         : integer;
begin
  fixedCols := kgGridName.FixedCols;
  fixedRows := kgGridName.FixedRows;
  for intGridRow := 0 to intNumberOfRows - 1 do
  begin
    AnItem := AEntretiens[intGridRow];
    ARow := intGridRow + FixedRows;
    for i := 0 to AnItem.PropertyCount - 1 do
    begin
      kgGridName.Cells[i + FixedCols, ARow] := AnItem.PropertyString[i];
    end;
  end;
end;

只需填写 Tentretien 类中的 GetPropertyCount 和 GetPropertyString 实现部分即可。

这种方法可能看起来和您的示例一样效率低下,因为必须手动编码所有属性值。但按照我的示例进行操作符合编程中的两个基本原则:

  • 不要重复自己的话。如果要填充许多网格,则必须在许多地方重复该代码。现在它在 Collection 项目中一劳永逸地声明。如果您重新设计该项目,只需更新两个功能即可。
  • 限制范围。程序的 GUI 部分应该尽可能少地了解集合项类。

关于delphi - 有效地将 delphi/freepascal 集合复制到网格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10744405/

相关文章:

delphi - 在Delphi XE中删除TBitmap上的矩形

java - 无法弄清楚如何按这些条件对列表进行排序

java - 将字符串值列表传递给参数化的 JUnit 测试

asp.net - Obout Grid 仅在客户端添加对象

python - 在python中将随机整数添加到网格的外部单元格

windows - Delphi 中的 Sqrt 函数

Delphi、TAdoConnection、Azure SQL 托管实例

Delphi - 有关记录中方法的 RTTI 信息

java - Collectors.toMap() 中映射的默认值

sorting - 如何对 EXTJS 中的日期列进行排序