Autor Beitrag
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Mi 26.02.14 23:49 
Hallo,

TList.sort braucht ja eine Callback-Function, in der das Vergleichskriterium untergebracht wird, Aufruf also: TList.sort(@callback(...));

Die Callback-Function darf keine Methode einer Klasse sein, da gibt es die Compiler-Fehlermeldung, dass es eine einfache Funktion sein muss. (Logisch, sonst müsste ja auch der Kontext des jeweiligen Objekts an TList.Sort übergeben werden.)

Die Callback-Function als lokale Funktion in der Methode zu definieren, in der das TList.Sort aufgerufen wird, überlistet zwar den Compiler, aber der Zugriff in der Callback-Function auf Variablen, die in der Klasse definiert sind, führt zu einer Exception, auch logisch wie oben.

Einzige bisher gefundene (laufende) Lösung: Die Callback-Function außerhalb jeder Klasse in der Unit definieren und die erforderlichen Parameter auch als global in der Unit definieren (siehe unten). Das kann ja aber im Sinn des Klassen-Konzeptes nicht richtig sein. Hat da jemand eine korrekte Lösung?

Viele Grüße
GuaAck


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
Unit Unit1;
...

TMyForm = class(TForm)
...
MyList: TList;
PROCEDURE sortiere_es;
....
END;

Implementation

VAR
  sortierkriterium: integer;

FUNCTION callback(...):integer;
  BEGIN
  IF sortierkriterium= ...
    ...
  END;

PROCEDURE TMyForm.sortiere_es;
  BEGIN
  ....
  sortierkriterium:=...;
  MyList.sort(@callback);
  ...
  END;
END;
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Do 27.02.14 05:49 
Eine Möglichkeit wäre, eine abgeleitete TList, z.B. TSortList zu definieren und dann das Quicksort selber mit all den Kriterien als Methode dieser Komponente zu implementieren. Der Vorteil wäre a) die Kapselung und b) die Möglichkeit, alternative Sortiermethoden, die vielleicht schneller sind, dort einzubinden. Nachteil ist natürlich, dass die Sortiererei selber verwaltet werden muss. Und mit Override kann man soweit ich weiß auch keine Prozedure mit einer komplett anderen Parameterstruktur, denn man benötigt ja dann die Vergleichsprozedur nicht mehr, nicht überschreiben. Außer man übernimmt die gleiche Prozedurstruktur der Sortfunktion von TList, übergibt aber NIL als Parameter, dann aber logischerweise nie ein Zugriff auf die überordnete Sortfunktion der Elternklasse (TList).

Was meinst Du zu diesem Vorschlag?

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.


Zuletzt bearbeitet von Tranx am Do 27.02.14 17:52, insgesamt 1-mal bearbeitet
Nersgatt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: Do 27.02.14 08:31 
Du könntest natürlich auch verschiedene Callbacks für die verschiedenen Kriterien anlegen. Wenn es nur um ein Sortierkriterium geht, wie in Deinem Beispiel, würde ich das für legitim halten:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
PROCEDURE TMyForm.sortiere_es;
  BEGIN
  ....
  sortierkriterium:=...;

  if (Sortierkriterium = skAufsteigend) then
    MyList.Sort(@callback_Aufsteigend)
  else 
    MyList.sort(@callback_Absteigend);
  ...
  END;
END;


So in der Art.
Wenn Du aber noch mehr Sachen im Callback abfragen müsstest, dann würde ich auch TList ableiten, und .Sort mit etwas eigenem überschreiben. Wenn Du in die Quellen von TList schaust, wirst Du feststellen, dass da gar nicht so viel dahinter steckt. Das kannst Du leicht kopieren und für Dich anpassen.

_________________
Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 27.02.14 11:16 
user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
Einzige bisher gefundene (laufende) Lösung: Die Callback-Function außerhalb jeder Klasse in der Unit definieren und die erforderlichen Parameter auch als global in der Unit definieren (siehe unten). Das kann ja aber im Sinn des Klassen-Konzeptes nicht richtig sein.
Weshalb man das seit Delphi 2009 ja auch z.B. mit anonymen Methoden lösen kann. Aber das geht bei deiner Delphiversion ja noch nicht.
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 174
Erhaltene Danke: 43



BeitragVerfasst: Do 27.02.14 18:47 
Abhängig von dem was eigentlich erreicht werden soll, könnte ich mir diese Varianten vorstellen:
- Ableitung von TList
- Class-Helper
- eigenständige Sortierklasse der eine Liste übergeben wird

In jedem Fall muss zumindest Sort und Quicksort(oder vergleichbar) neu implementiert werden.
z.B.:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
IComperator = interface(IInterface)
  {GUID}
  function Compare(Item1, Item2: Pointer): Integer
end;

TMyList = class(TList)
private
  procedure QuickSort(L, R: Integer; const AComperator: IComperator);
public
  procedure Sort(const AComperator: IComperator); reintroduce;
end;

TMyComperator = class(TInterfacedObject, IComperator)
  constructor Create(AParam1: Boolean; AParam2: Integer);
private
  FParam1: Boolean;
  FParam2: Integer;
public
  function Compare(Item1, Item2: Pointer): Integer;
end;

MyList.Sort(TMyComperator.Create(True, 5));
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Do 27.02.14 19:17 
Wie man (bei meinem Delphi 5.0) in der unit Classes sehen kann, ist die grundlegende Sortierungsprozedur eh außerhalb der Klasse TList:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
implementation 

:
:

procedure QuickSort(SortList: PPointerList; L, R: Integer;
  SCompare: TListSortCompare);

var
  I, J: Integer;
  P, T: Pointer;
begin
  repeat
    I := L;
    J := R;
    P := SortList^[(L + R) shr 1];
    repeat
      while SCompare(SortList^[I], P) < 0 do
        Inc(I);
      while SCompare(SortList^[J], P) > 0 do
        Dec(J);
      if I <= J then
      begin
        T := SortList^[I];
        SortList^[I] := SortList^[J];
        SortList^[J] := T;
        Inc(I);
        Dec(J);
      end;
    until I > J;
    if L < J then
      QuickSort(SortList, L, J, SCompare);
    L := I;
  until I >= R;
end;


Also ist es doch eigentlich egal, dass dann die Funktion Compare auch außerhalb der Klasse definiert ist, oder? Wenn man das alles in einer Klasse behalten will, ist doch eigentlich nur die Überladung mit reintroduce und die Einfügung der Methoden Quicksort und SCompare in die Klasse sinnvoll. Bei Quicksort bräuchte man dann ja den Parameter Sortlist nicht mehr, da man ja auf die Liste selber zugreift, also über die Property Items.

in etwa so:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
implementation

TMyList = Class(TList)
          public
            function SCompare(Item1, Item2 : Pointer) : integer;
            procedure Quicksort(L, R : Integer);
          end;

implementation


procedure TMyList.QuickSort(L, R: Integer);

var
  I, J: Integer;
  P, T: Pointer;
begin
  repeat
    I := L;
    J := R;
    P := Items[(L + R) shr 1];
    repeat
      while SCompare(Items[I], P) < 0 do
        Inc(I);
      while SCompare(Items[J], P) > 0 do
        Dec(J);
      if I <= J then
      begin
        T := Items[I];
        Items[I] := Items[J];
        Items[J] := T;
        Inc(I);
        Dec(J);
      end;
    until I > J;
    if L < J then
      QuickSort(L, J);
    L := I;
  until I >= R;
end;

{(Sortierroutine-Beispiel für Strings)}

function TMyList.SCompare(Item1, Item2 : Pointer) : integer;
var
   s1, s2 : ^string;
begin
  s1 := Item1;
  s2 := Item2;
  if (s1^>s2^) then
    Result := 1
  else if (s1^<s2^) then
    Result := -1
  else
    Result := 0;
end;
:
:

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Fr 28.02.14 01:31 
Danke an alle,

anscheinend ist es ja wirklich eine Unvollkommenheit in Delphi 7, die später mit den "anonymen..." behoben wurde.

Quicksort nutze ich als Procedure seit langer Zeit. Tlist ist sehr praktisch und ich komme ja klar. Nur von der Klassenidee konnte ich mir nicht vorstellen, dass es so richtig ist, wie ich es mache.

Beste Grüße
GuaAck
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Fr 28.02.14 05:57 
Die Lösung, die Vergleichsprozedur auszulagern, ich habe mal drüber nachgedacht, ist wohl deswegen so passend, weil sie flexibel ist. Ich kann verschiedenste Datentypen vergleichen. Schließlich ist der Vergleich ja unterschiedlich, ob ich Zahlen, Datumsangaben, Strings ... vergleiche. Daher ist jede eingebettete Lösung auch etwas Einschränkender und damit nicht mehr so flexibel.

Als Lösung habe ich mir gedacht, man könnte ja in der neu erzeugten TMyList auch eine Integer-Eigenschaft Typus einbetten. Die könnte dann in der Vergleichsprozedur dafür gedacht sein, die richtigen Variablentypen zur Verzweigung zu verwenden z.B.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
const
  isInteger = 1;
  isReal = 2;
  isString = 3;
  :
  isUnknown = 255;

type 
  TMyList = class(TList);
           fTypus : integer;

          function SCompare(p1, p2 : pointer) : integer;

          :
          property Typus : integer Read GetTypus write SetTypus;


          end;

  function TMyList.SCompare(p1, p2 : pointer) : integer;

  var
    s1, s2 : ^string;
    i1, i2 : ^longint;
    r1, r2 : ^extended;


  begin
    if Typus = isInteger then
    begin
      s1 := p1;
      s2 := p2;    
      if (s1^>s2^) then
        Result := 1
      else if (s1^<s2^) then
        Result := -1
      else
        Result := 0;
    end
    else if Typus = isReal then
    begin
      r1 := p1;
      r2 := p2;    
      if (r1^>r2^) then
        Result := 1
      else if (r1^<r2^) then
        Result := -1
      else
        Result := 0;
    end
    else if Typus = isInteger then
    begin
      i1 := p1;
      i2 := p2;    
      if (i1^>i2^) then
        Result := 1
      else if (i1^<i2^) then
        Result := -1
      else
        Result := 0;
    end
    :
// weitere Typen (z.B. Zit, Datum, ...)
    else
// falls Typus nicht bekannt, Null ausgeben
      Result := 0;
  end;



Dann wäre eine gewisse Flexibilität gegeben. In der Createprozedur (Konstruktor) müsste dann der Typus mit isUknown vorbelegt werden, das ist dann alles. Und natürlich der Typus manuell gesetzt werden. Denn bei Erstellen der Liste weiß man ja, was dort gespeichert sein soll. Und Strings mit Zahlen zu vergleichen macht echt wenig Sinn, außer ich will die möglichen Zahlen als Zahl nehmen, und die strings als Strings. Doch wie soll das Ganze dann sortiert werden? Man kann m.E. nur gleiche Typen sinnvoll vergleichen.

Das als einen Ansatz.

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Fr 28.02.14 11:03 
Wäre da eine Property nicht flexibler? Also etwas in der Art
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
type
  TListCompareMethod = function(Item1, Item2: Pointer): integer of object;

  TMyList = class(TList)
  private
    FCompareMethod: TListCompareMethod;
    ...
  public
    property OnCompare: TListCompareMethod read FCompareMethod write FCompareMethod;
    ...
  end;
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 174
Erhaltene Danke: 43



BeitragVerfasst: Fr 28.02.14 18:51 
Die Vergleichsfunktion als Methode der Liste anzulegen, erscheint mir nicht sinnvoll.
Diese ist vom Anwendungsfall abhängig, ein neuer Anwendungsfall kann auch eine neue Sortierreihenfolge erfordern.
Da möchte ich nicht jedesmal die Datenklasse bzw. Liste erweitern.
Ob die Vergleichsfunktion als Property oder als Parameter übergeben wird, ist eher nebensächlich.

Ich würde den Vergleich (wie in meinem Beispiel) sogar in eine Klasse auslagern.
Damit wird optimale Flexibilität(z.B. beliebige Parameter) mit Wiederverwendbarkeit kombiniert.

Für diesen Beitrag haben gedankt: Tranx
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Fr 28.02.14 19:24 
user profile iconBlup hat folgendes geschrieben Zum zitierten Posting springen:
Die Vergleichsfunktion als Methode der Liste anzulegen, erscheint mir nicht sinnvoll.
Diese ist vom Anwendungsfall abhängig, ein neuer Anwendungsfall kann auch eine neue Sortierreihenfolge erfordern.
Da möchte ich nicht jedesmal die Datenklasse bzw. Liste erweitern.
Ob die Vergleichsfunktion als Property oder als Parameter übergeben wird, ist eher nebensächlich.

Ich würde den Vergleich (wie in meinem Beispiel) sogar in eine Klasse auslagern.
Damit wird optimale Flexibilität(z.B. beliebige Parameter) mit Wiederverwendbarkeit kombiniert.


Dem kann ich eigentlich nur zustimmen. Denn alle Fälle wird man nie abdecken, weil in TList ja alles gespeichert werden kann, was man sich vorstellen kann, oder auch nicht vorstellen kann. Ich bin mir auch 100%ig sicher, das genau aus diesem Grund auch beides: sowohl die Sortierprozedur als auch Vergleichsfunbktion, ausgelagert wurde. Den auch die Sortierprozedur selber kann sich ja auch ändern.

Wenn man partout das in die Klasse integrieren will, dann muss man selber beides programmieren, darum kommt man nicht drumrum. Und um es dann flexibel zu gestalten fiel mir - jetzt spinne ich mal, denn ich weiß nicht recht, wei man es umsetzen könnte - eine Ereignisprozedur "OnSort" ein. Aber ganz erhlich, ich sehe selbst darin keinen Vorteil. Aber vielleicht hat ja der Threadstarter neben der prinzipiellen Frage einer Kapselung aller Prozeduren eine konkrete Anwendung im Kopf. Dann kann man darüber dan sich Gedanken machen. So, wie das jetzt implementiert ist, ist es wohl am flexibelsten.

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Fr 28.02.14 21:07 
Hallo Alle,

da scheine ich ja ein aufregendes Thema angeschnitten zu haben, vielen Dank für die vielen guten Ideen.

Der "Threadstarter" hat als konkretes Problem eine TStringlist, die er mit Click auf den jeweiligen Spaltenkopf nach der Spalte sortieren möchte.

Meine Lösung: Vor dem Sortieren trage ich in jeden Tlist-Eintrag in einem Feld das Sortierkriterium ein. Dann kann ich das Compare in einer lokalen Funktion in der
Methode aufrufen, die auch das TList.Sort aufruft. Somit ist alle in der Klasse gekapselt.

Gruß
GuaAck
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Sa 01.03.14 13:22 
Frage, wenn Du eine Stringliste mit Spalten hast, warum nicht eine TStringGrid? Das ist schon in Spalten organisiert. Allerdings habe ich gesehen, dass die Sortierung dort nicht gerade einfach zu organisieren ist, da die Einträge in den Spalten und Zeilen als TStrings ansprechbar sind, und diese leider nicht sortiert werden können. Eine komplett andere Art wäre dann TDBGrid und die Daten in einer Datenbanktabelle. Dann kannst Du die Tabelle sortieren, was dann der entsprechende Datenbanktreiber für Dich übernimmt. Dann benötigst Du keine Sort-Methode, bloß ein Klick auf die Titelzeile und Du schreibst - bei einer TQuery als Datenbankkomponente - zum Beispiel:


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm1.dbgListeTitleClick(Column: TColumn);

begin
  Tabelle.Active := FALSE;
  Tabelle.SQL.Text := "Select * FROM '#10#13'TabellenDaten'#10#13'ORDER BY '+Column.FieldName;
  Tabelle.Active := TRUE;
end;


Dann benötigst Du die Tabelle "Tabellendaten" und die Komponente dgbListe.

Dann allerdings müsstest Du die Daten in die Tabelle eintragen. Ich weiß ja nicht, wie groß Deine Liste ist und ob die sich ändert.

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 01.03.14 15:15 
Auch wenn es langweilig wird (weil ich das oft schreibe ;-)), aber das ist ein typischer Fall für eine TVirtualStringTree. ;-)
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Sa 01.03.14 18:27 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Auch wenn es langweilig wird (weil ich das oft schreibe ;-)), aber das ist ein typischer Fall für eine TVirtualStringTree. ;-)


Gibt es das schon in Delphi 7?

Frage geklärt, habe gesehen, dass es ab Delphi 6 existiert.

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Sa 01.03.14 23:53 
Hallo,

auch wenn ich die Frage als erledigt markiert habe, läuft die Diskussion noch:

Zu TVirtualStringTree: Ist in meinem Delphi 7 Personal nicht enthalten. Mein Delphi 6 Professionel habe ich leider verkauft, der Personal-Umfang (und Lizenz!) reichte mir damals im Grunde. Außerdem: Es ist kein Tree.

TStringList, TStringGrid: Das verwechsele ich immer und habe mich in meinem Beitrag geirrt. Ich nutze TStringGrid, das aber eben kein sort bietet.

Hier noch einmal im Kürze meine Lösung, die gut ist und Potenzial für weitere Verfeinerungen hat:

a) Im TForm ist es ein TStringGrid.

b) Im Hintergrund gibt es eine TList mit den Zeilen, die im TStringrid dargestellt werden sollen. Nach einer Neusortierung wird TList nach TStringlist kopiert, wobei auch z. B. inttostr genutzt wird.
Es handelt sich um etwa 1000 Zeilen und 10 Spalten, ich habe kein Performance Problem (auch nicht auf meiner zu-Hause-Uralt-800MHz-CPU).

c) In TList habe ich eine Spalte zusätzlich definiert, die das Sortierkriterium angibt, das könnte aber auch ein Pointer auf eine andere Struktur sein. Jedenfalls hat man dann über den Zeilen-Pointer in der Compare-Routine Zugriff auf die Variablen in dieser Zusatzstruktur.

Geht bestens, ist übersichtlich, ist als Klasse gekapselt, also genau das was ich brauchte, als Resultat der Diskussion in dieme Forum!

Beste Grüße
GuaAck
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 02.03.14 00:02 
user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
Zu TVirtualStringTree: Ist in meinem Delphi 7 Personal nicht enthalten. Mein Delphi 6 Professionel habe ich leider verkauft, der Personal-Umfang (und Lizenz!) reichte mir damals im Grunde. Außerdem: Es ist kein Tree.
Nein, es muss selbst installiert werden, das stimmt.
TVirtualStringTree heißt nur Tree, das ist genauso gut als Grid nutzbar oder sogar als Kombination von beidem.

Der Thread und das Bild sind uralt, aber auch da habe ich ein solches Grid benutzt, was du in dem Bild siehst ist eine TVirtualStringTree:
www.entwickler-ecke....ar+RC+1_64090,0.html