2012-05-24 2 views
1

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를 제안했지만 사용 방법을 모른다.

고마워,

JDaniel 여기

+0

소유자 도면 사용에 대해 생각해 보셨습니까? 그렇게하면 그리드에서 실제로 볼 수있는 콜렉션 부분에만 액세스해야합니다. 뻔뻔한 플러그 : TdzVirtualStringGrid [dzlib] (http://sourceforge.net/p/dzlib/code/125/tree/) – dummzeuch

답변

3

는 델파이 강화 된 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의 의견에서 언급했듯이 향상된 RTTI는 Lazarus/FreePascal에서 구현되지 않습니다.

모든 플랫폼에 대한 일반적인 솔루션은 속성 값을 가져올 수있는 컬렉션 항목 기본 클래스를 추가하는 것입니다.

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 구현의 일부를 입력합니다.

이 방법을 사용하면 모든 속성 값을 직접 코딩해야하므로 예제가 비효율적으로 보일 수 있습니다. 하지만 제 예제는 프로그래밍의 두 가지 기본 원칙을 준수합니다.

  • 반복하지 마십시오. 채울 그리드가 많으면 코드를 여러 위치에서 반복해야합니다. 이제 컬렉션 항목 내에서 단 한 번에 선언되었습니다. 항목을 다시 디자인해야한다면 두 기능 만 업데이트하면됩니다.
  • 범위를 제한적으로 유지하십시오. 프로그램의 GUI 부분은 컬렉션 항목 클래스에 대해 가능한 한 최소한을 알아야합니다.
+0

+1. 멋진 Delphi 구현이지만 Lazarus/FreePascal에서도 작동합니까? 나는 그들이 향상된 RTTI를 지원한다고 생각하지 않는다. –

+0

@KenWhite, 고마워. FreePascal 옵션을 완전히 간과했습니다. 답변을 수정했습니다.여기 [delphi_language_features_which_fpc_does_not_have] 링크 (http://wiki.freepascal.org/delphi_language_features_which_fpc_does_not_have). –

+1

:-) 저는 FP에서 작동하지 않는다는 것을 알고있었습니다. 단지 그 질문의 절반 정도를 정중하게 생각하고 싶었습니다.

관련 문제