Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Delphi 7 version</strong> Here's an example of how to achieve that. I used Delphi2010 to implement it but it should work in Delphi7 at least as I used TypInfo unit directly.</p> <pre><code>unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) ListBox1: TListBox; Edit1: TEdit; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } FList: TList; procedure DoSort(PropName: String); procedure DoDisplay(PropName: String); public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} uses TypInfo; var PropertyName: String; type TPerson = class private FName: String; FAge: Integer; published public constructor Create(Name: String; Age: Integer); published property Name: String read FName; property Age: Integer read FAge; end; { TPerson } constructor TPerson.Create(Name: String; Age: Integer); begin FName := Name; FAge := Age; end; function ComparePersonByPropertyName(P1, P2: Pointer): Integer; var propValueP1, propValueP2: Variant; begin propValueP1 := GetPropValue(P1, PropertyName, False); propValueP2 := GetPropValue(P2, PropertyName, False); if VarCompareValue(propValueP1, propValueP2) = vrEqual then begin Result := 0; end else if VarCompareValue(propValueP1, propValueP2) = vrGreaterThan then begin Result := 1; end else begin Result := -1; end; end; procedure TForm1.FormCreate(Sender: TObject); begin FList := TList.Create; FList.Add(TPerson.Create('Zed', 10)); FList.Add(TPerson.Create('John', 20)); FList.Add(TPerson.Create('Mike', 30)); FList.Add(TPerson.Create('Paul', 40)); FList.Add(TPerson.Create('Albert', 50)); FList.Add(TPerson.Create('Barbara', 60)); FList.Add(TPerson.Create('Christian', 70)); Edit1.Text := 'Age'; DoSort('Age'); // Sort by age DoDisplay('Age'); end; procedure TForm1.Button1Click(Sender: TObject); begin DoSort(Edit1.Text); DoDisplay(Edit1.Text); end; procedure TForm1.DoSort(PropName: String); begin PropertyName := PropName; FList.Sort(ComparePersonByPropertyName); end; procedure TForm1.DoDisplay(PropName: String); var i: Integer; strPropValue: String; begin ListBox1.Items.Clear; for i := 0 to FList.Count - 1 do begin strPropValue := GetPropValue(FList[i], PropName, False); ListBox1.Items.Add(strPropValue); end; end; end. </code></pre> <p>BTW, I used a simple form with a <em>listbox</em>, an <em>edit</em> and a <em>button</em>. The listbox shows the contents of the list (FList) sorted. The button is used to sort the list according to what the user has typed in the editbox.</p> <p><strong>Delphi 2010 version</strong> (uses references to methods)</p> <pre><code>unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm2 = class(TForm) ListBox1: TListBox; Edit1: TEdit; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } FList: TList; FPropertyName: String; { &lt;&lt; } procedure DoSort(PropName: String); procedure DoDisplay(PropName: String); function CompareObjectByPropertyName(P1, P2: Pointer): Integer; { &lt;&lt; } public { Public declarations } end; var Form2: TForm2; implementation {$R *.dfm} uses TypInfo; type TPerson = class private FName: String; FAge: Integer; published public constructor Create(Name: String; Age: Integer); published property Name: String read FName; property Age: Integer read FAge; end; { TPerson } constructor TPerson.Create(Name: String; Age: Integer); begin FName := Name; FAge := Age; end; /// This version uses a method to do the sorting and therefore can use a field of the form, /// no more ugly global variable. /// See below (DoSort) if you want to get rid of the field also ;) function TForm2.CompareObjectByPropertyName(P1, P2: Pointer): Integer; { &lt;&lt; } var propValueP1, propValueP2: Variant; begin propValueP1 := GetPropValue(P1, FPropertyName, False); propValueP2 := GetPropValue(P2, FPropertyName, False); if VarCompareValue(propValueP1, propValueP2) = vrEqual then begin Result := 0; end else if VarCompareValue(propValueP1, propValueP2) = vrGreaterThan then begin Result := 1; end else begin Result := -1; end; end; procedure TForm2.FormCreate(Sender: TObject); begin FList := TList.Create; FList.Add(TPerson.Create('Zed', 10)); FList.Add(TPerson.Create('John', 20)); FList.Add(TPerson.Create('Mike', 30)); FList.Add(TPerson.Create('Paul', 40)); FList.Add(TPerson.Create('Albert', 50)); FList.Add(TPerson.Create('Barbara', 60)); FList.Add(TPerson.Create('Christian', 70)); Edit1.Text := 'Age'; DoSort('Age'); // Sort by age DoDisplay('Age'); end; procedure TForm2.Button1Click(Sender: TObject); begin DoSort(Edit1.Text); DoDisplay(Edit1.Text); end; procedure TForm2.DoSort(PropName: String); begin FPropertyName := PropName; { &lt;&lt; } FList.SortList(CompareObjectByPropertyName); { &lt;&lt; } /// The code above could be written with a lambda, and without CompareObjectByPropertyName /// using FPropertyName, and by using a closure thus referring to PropName directly. /// Below is the equivalent code that doesn't make use of FPropertyName. The code below /// could be commented out completely and just is there to show an alternative approach. FList.SortList( function (P1, P2: Pointer): Integer var propValueP1, propValueP2: Variant; begin propValueP1 := GetPropValue(P1, PropName, False); propValueP2 := GetPropValue(P2, PropName, False); if VarCompareValue(propValueP1, propValueP2) = vrEqual then begin Result := 0; end else if VarCompareValue(propValueP1, propValueP2) = vrGreaterThan then begin Result := 1; end else begin Result := -1; /// This is a catch anything else, even if the values cannot be compared end; end); /// Inline anonymous functions (lambdas) make the code less readable but /// have the advantage of "capturing" local variables (creating a closure) end; procedure TForm2.DoDisplay(PropName: String); var i: Integer; strPropValue: String; begin ListBox1.Items.Clear; for i := 0 to FList.Count - 1 do begin strPropValue := GetPropValue(FList[i], PropName, False); ListBox1.Items.Add(strPropValue); end; end; end. </code></pre> <p>I marked with <code>{ &lt;&lt; }</code> the main changes.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload