2010-09-16 13 views
7

मेरे पास एक टीएलआईस्ट है। इसमें एक ही प्रकार की वस्तुओं का संग्रह होता है। ये वस्तुएं एक टीपीर्सिस्टेंट से निकली हैं, और लगभग 50 विभिन्न प्रकाशित गुण हैं।मैं डेल्फी में ऑब्जेक्ट्स की मनमानी संपत्ति पर एक टीएलिस्ट को कैसे क्रमबद्ध कर सकता हूं?

मेरे आवेदन में, उपयोगकर्ता इन ऑब्जेक्ट्स की खोज जारी कर सकता है, और खोज के परिणाम TDrawGrid में प्रदर्शित होते हैं, जिसमें खोज किए जा रहे गुणों के आधार पर प्रदर्शित विशिष्ट कॉलम होते हैं। उदाहरण के लिए, यदि उपयोगकर्ता 'चालान' पर खोज करता है, तो 'ग्रिड' परिणामों में 'चालान' कॉलम प्रदर्शित होता है। मैं उपयोगकर्ता को इस ग्रिड को सॉर्ट करने में सक्षम होना चाहता हूं। किकर, ज़ाहिर है, मैं यह नहीं जानता कि ग्रिड में कौन से कॉलम हैं।

आम तौर पर एक टीएलआईटी को सॉर्ट करने के लिए, मैं सिर्फ एक कार्य करता हूं, जैसे कि SortOnName(p1, p2), और टीएलिस्ट की sort() विधि को कॉल करें। मैं एक कदम आगे जाना चाहता हूं और सॉर्ट विधि में संपत्ति का नाम पास करने का तरीका ढूंढ सकता हूं और तुलना करने के लिए आरटीटीआई का उपयोग कर सकता हूं।

मैं निश्चित रूप से 50 अलग-अलग प्रकार के तरीकों को बना सकता हूं और इसका उपयोग कर सकता हूं। या, सॉर्टिंग विधि को सॉर्ट करने के तरीके को इंगित करने के लिए इस काम को करने के लिए वैश्विक स्तर पर या कक्षा के हिस्से के रूप में एक चर सेट करें। लेकिन मैं उत्सुक था कि अगर डेल्फी समर्थक के बाहर इस पर लागू करने के तरीके पर अन्य विचार थे।

उत्तर

6

डेल्फी 7 संस्करण यहां प्राप्त करने का एक उदाहरण यहां दिया गया है। मैंने इसे लागू करने के लिए डेल्फी -2010 का उपयोग किया, लेकिन इसे कम से कम डेल्फी 7 में काम करना चाहिए क्योंकि मैंने सीधे टाइपपॉन्फो इकाई का उपयोग किया था।

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. 

Btw, मैं एक लिस्टबॉक्स, एक संपादित और एक बटन के साथ एक सरल फार्म का उपयोग किया। सूची बॉक्स क्रमबद्ध सूची (FList) की सामग्री दिखाता है। बटन को संपादन बॉक्स में जो टाइप किया गया है उसके अनुसार सूची को सॉर्ट करने के लिए उपयोग किया जाता है।

डेल्फी 2010 संस्करण (तरीकों के लिए संदर्भ का उपयोग करता है)

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; { << } 
    procedure DoSort(PropName: String); 
    procedure DoDisplay(PropName: String); 
    function CompareObjectByPropertyName(P1, P2: Pointer): Integer; { << } 
    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; { << } 
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; { << } 
    FList.SortList(CompareObjectByPropertyName); { << } 

    /// 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. 

मैं { << } मुख्य परिवर्तन के साथ चिह्नित।

+0

ओह, यदि आपके पास डेल्फी -2010 है तो आप ग्लोबल वैरिएबल से छुटकारा पाने के लिए ग्लैम्बिक वैरिएबल से छुटकारा पाने के लिए एक लैम्बडा का उपयोग कर सकते हैं और सॉर्टलिस्ट() – Trinidad

+2

धन्यवाद त्रिनिदाद का उपयोग करना होगा। शायद वह दृष्टिकोण जो मैं ऊपर (कोड ऊपर) का उपयोग कर समाप्त करूंगा। मुझे लगता है कि एकमात्र अन्य विकल्प एक वंशज टीएलिस्ट बनाने और अपने स्वयं के त्वरित प्रकार को लागू करना है जो एक संपत्ति नाम पैरामीटर स्वीकार करेगा, या कम से कम एक विधि के बजाय विधि विधि के पैरामीटर के रूप में एक विधि (ऑब्जेक्ट की प्रक्रिया) स्वीकार करेगा । – GrandmasterB

3

डेल्फी> = 200 9 में अपग्रेड करें, और फिर आप सीधे कार्यसूची को TList.Sort में पास करने के लिए अज्ञात विधियों का उपयोग कर सकते हैं।

एक उदाहरण http://delphi.about.com/od/delphitips2009/qt/sort-generic.htm

मैं किसी अन्य तरीके से की पता नहीं है, अन्य तरीकों आप अपने प्रश्न में वर्णन से पाया जा सकता है।

+0

धन्यवाद, लेकिन मुझे यकीन नहीं है कि यह चाल चलती है क्योंकि सॉर्टिंग फ़ंक्शन को अभी भी यह जानने का तरीका चाहिए कि किस संपत्ति को सॉर्ट करना है, जिसे केवल रनटाइम पर जाना जाता है। (मेरे पास डी 2010 है, बीटीडब्ल्यू) – GrandmasterB

+0

लेकिन आप उस ज्ञात-पर-रनटाइम संपत्ति को पैरामीटर के रूप में पास करेंगे। कुछ लिखने वाले कोड को लिखें, और फिर उसे बताएं कि कुछ रनटाइम पर कौन सा है। –

+1

मुझे समस्या हां दिखाई देती है, आपको यह जानने के लिए केस स्टेटमेंट करना पड़ सकता है कि अज्ञात विधि में क्या तुलना करना है, उदा। MyList.Sort (TComparer .Construct ( समारोह (स्थिरांक एल, आर: TMyObj): पूर्णांक शुरू अगर Edit1 = 'उम्र' तो परिणाम: = CompareValue (L.Age, R.Age) अंत )); –

संबंधित मुद्दे