Delphi - ListView elemeinek rendezése a fejlécre való kattintással

forráskód letöltése
Ebben a cikkben a TListView komponens egy továbbfejlesztését mutatjuk be. Az új komponensben a megfelelő oszlop fejlécére történő kattintás után a kiválasztott oszlop szerint lesznek sorbarendezve az adatok. A mellékelt példaprogram megnyitása előtt a SortListView.pas-ban lévő komponenst telepítenie kell a Delphi alá.

A TListView komponenshez képest csupán két új property-t adunk. Az Ascend egy logikai típusú property, True érték esetén a rendezés növekvő, míg False esetén csökkenő. A SortColumn határozza meg, hogy melyik oszlopban található adatok szerint kell sorbarendezni a listát. Ebben a property-ben az oszlop sorszámát kell megadni (0=első oszlop, 1=második oszlop, stb.).
Futásidőben a megfelelő oszlop fejlécre kattintva az adatok annak megfelelően lesznek rendezve. Ha a felhasználó újból arra az oszlopra kattint, ami szerint sorba vannak rendezve az adatok, akkor a rendezés iránya megfordul.

A megvalósítás:
A TListView továbbfejlesztéséről van szó, tehát ebből az osztályból származtatjuk az új komponensünket. Léterhozunk egy CompareItems eljárást, amely a rendezés közben összehasonlítandó két elemről dönti el, hogy a listában melyik szerepel előbb.
procedure CompareItems(Sender: TObject; Item1, Item2: TListItem; Data: Integer; var Compare: Integer);

A komponens konstruktorában ezt az eljárást rendeljük hozzá az OnCompare eseményhez.
constructor TSortListView.Create;
begin
    inherited Create(aOwner);
    OnCompare:=CompareItems;
end;
A Compare paraméter értéke határozza meg a két elem (Item1 és Item2) sorrendjét. Ha a két elem egyforma, akkor az értéke 0, ha az Item1>Item2 akkor értéke nagyobb, mint 0, és ha Item1<Item2 akkor az értéke kisebb, mint 0.
procedure TSortListView.CompareItems;
var i1, i2, itmp:string;
    v1, v2:boolean;
begin
    v1:=(FSortColumn<=Item1.SubItems.Count);
    v2:=(FSortColumn<=Item2.SubItems.Count);
A v1 és v2 változókban tároljuk, hogy az éppen összehasonlítandó sorokban az adott oszlopban van-e adat, vagy sem. Ha mindkét sorban van adat, akkor összehasonlítjuk a két adatot. Az első oszlopban (FSortColumn=0) a ListItem Caption property-jét kell összehasonlítani, mert a ListView-ban az első oszlopban ez jelenik meg. A többi oszlopban a SubItems megfelelő elemét kell vizsgálni.
    if (v1) and (v2) then
    begin
        if FSortColumn=0 then
        begin
            i1:=Item1.Caption;
            i2:=Item2.Caption;
        end else
        begin
            i1:=Item1.SubItems[FSortColumn-1];
            i2:=Item2.SubItems[FSortColumn-1];
        end;
Ha a sorrend fordított (FAscend=FALSE), akkor felcseréljük a két elemet.
        if NOT FAscend then
        begin
            itmp:=i1;
            i1:=i2;
            i2:=itmp;
        end;
Az összehasonlítást az AnsiCompareText függvénnyel végezzük, melynek visszatérési értéke pont megfelel nekünk a Compare változónak.
    
        Compare:=AnsiCompareText(i1, i2);
    end
Ha bármelyik sorban nincs adat, akkor úgy végezzük az összehasonlítást, mintha a hiányzó adat helyett egy üres sztring lenne, tehát növekvő rendezés esetén az üres adat kerül előre, csökkenő esetén pedig fordítva.
    else
    begin
        if v1 then Compare:=1 else Compare:=-1;
        if FAscend then Compare:=-Compare;
    end;
end;
A rendezést tehát ezzel le is tudtuk. Van azonban még egy fontos feladatunk, méghozzá az hogy eldöntsük, hogy melyik oszlop szerint kell rendezni az adatokat. A rendezés, mint mondtuk annak az oszlopnak megfelelően történik, amelyik fejlécén a felhasználó kattintott.
A ColClick metódus akkor fut le, ha a felhasználó valamelyik oszlop fejlécére kattintott. Ezt a metódust felülírva elkészítjük a saját ColClick metódusunkat:
procedure ColClick(Column: TListColumn); override;

procedure TSortListView.ColClick;
begin
    if FSortColumn=Column.Index then begin
        FAscend:=NOT FAscend;
    end else begin
        FSortColumn:=Column.Index;
        FAscend:=TRUE;
    end;
    AlphaSort;
end;
A Column paraméterben megkapjuk az oszlop fejlécének adatait, amelyből nekünk csak az Index változó értéke kell. Ez adja meg ugyanis az oszlop sorszámát (0=első, 1=második, stb.). Megnézzük, hogy a kiválasztott oszlop szerint vannak-e az adatok sorbarendezve, és ha igen, akkor megfordítjuk a sorrendet, ellenkező esetben átadjuk az FSortColumn változónak a kiválasztott oszlop index-ét, és a sorrendet növekvőre állítjuk be. Ezután meghívjuk az AlphaSort metódust, amely rendezni fogja a sorainkat.