Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi StringGrid in Treeview zeigen (https://www.delphipraxis.net/91307-stringgrid-treeview-zeigen.html)

DavidKlimas 3. Mai 2007 07:21


StringGrid in Treeview zeigen
 
Hallo,

ich brauche mal wieder Hilfe zum Treeview. Ich habe ein StringGrid mit n einträgen (manchmal 5, manchmal 500) und ich möchte dieses in einem Treeview abbilden. Jede spalte des StringGrids soll ein neuer "Child" der vorhergehenden Spalte sein. Das Prinzip :

Zeile1-1.Spalte
...Zeile1-2.Spalte
......Zeile1-3.Spalte
Zeile2-1.Spalte
...Zeile2-1.Spalte
Zeile3-1.Spalte
...Zeile3-2.Spalte
......Zeile3-3.Spalte

usw.

Ich bedanke mich für jegliche Hilfe...

messie 3. Mai 2007 08:46

Re: StringGrid in Treeview zeigen
 
Du musst Deine Einträge aus dem StringGrid als Textdatei oder Stream speichern und dann ins TreeView einlesen. Jede untergeordnete Ebene wird dann durch ein oder mehrere führende Tabs zugeordnet.
Bau Dir mal ein TreeView und speichere es mit TreeView.SaveToFile ab, dann sieht man gleich wie es funktioniert.
Delphi-Quellcode:
var
  sl : TStringList;
  sg : TStringGrid;
  i,j,k : integer;
  s : string;
begin
  for i := 1 to sg.RowCount do
  begin
    s := '';
    s := sg.Cells[i,1];  
    sl.Add(s);
    for j := 2 to sg.ColCount do
    begin
      s := '';
      for k := 1 to j-1 do
      begin
        s := s + #9;
      end;
      s := s + sg.Cells[i,j];
    end;
  end;
  sl.SaveToFile('irgendwas');//und die dann laden
end;
Grüße, Messie

Bernhard Geyer 3. Mai 2007 08:50

Re: StringGrid in Treeview zeigen
 
Falls ein paar € investiert werden können. Diverse Grids wie z.B. vom ElPack können sowas

marabu 3. Mai 2007 09:55

Re: StringGrid in Treeview zeigen
 
Hallo David,

wenn es wirklich nur um die Übernahme von Griddaten gehen sollte, dann geht das auch ohne Zwischenspeicherung:

Delphi-Quellcode:
procedure AddSubTree(tv: TTreeView; s: TStrings; iSkip: Integer);
var
  i: Integer;
  tn: TTreeNode;
begin
  tn := nil;
  for i := iSkip to Pred(s.Count) do
    tn := tv.Items.AddChild(tn, s[i]);
end;

procedure TDemoForm.ButtonClick(Sender: TObject);
var
  iRow: Integer;
begin
  with StringGrid do
    for iRow := FixedRows to Pred(RowCount) do
      AddSubTree(TreeView, Rows[iRow], FixedCols);
end;
Allerdings kann ich aufgrund deiner Beschreibung nicht erkennen, warum eine TreeView deine Daten besser visualisieren sollte als ein Grid.

Grüße vom marabu

DavidKlimas 3. Mai 2007 10:20

Re: StringGrid in Treeview zeigen
 
Eigentliches ziel ist es Zeilen des Stringgrids , die gleich anfangen zusammenzufügen. Als Beispiel :

ICE-Abfahrten mit Stationen im Stringgrid

Hamburg - Hannover - Kassel - Frankfurt
Berlin - Hannover - Düsseldorf - Köln - Saarbrücken
Hamburg - Bremen - Osnabrück
München - Nürnberg - Würzburg - Frankfurt
Berlin - Hannover - Düsseldorf - Osnabrück - Bremen

Das ist mein Stringgrid aktuell. Im Treeview will ich jetzt folgendes :

Hamburg
..+Hannover
.....+Kassel
........-Frankfurt
..+Bremen
.....-Osnabrück
Berlin
..+Hannover
.....+Düsseldorf
........+Köln
...........-Saarbrücken
........+Osnabrück
...........-Bremen
München
..+Nürnberg
.....+Würzburg
........-Frankfurt

hoika 3. Mai 2007 10:25

Re: StringGrid in Treeview zeigen
 
Hallo,

das sollte der virtual treeview von Lischke auch können.
Einfach mal googlen und sich die demos ansehen.


Heiko

Lannes 3. Mai 2007 12:10

Re: StringGrid in Treeview zeigen
 
Hallo,

die Funktion AddTreeNodePathDupIgnore aus der Delphi-Library der Entwickler-Ecke hilft Dir.

Auslesen des StringGrids und Aufruf der Funktion:
Delphi-Quellcode:
var z,i : Integer;
    ReNode : TTreeNode;
    s : String;
begin
  TreeView1.Items.BeginUpdate;
  TreeView1.Items.Clear;
  for z := 1 to Pred(StringGrid1.RowCount) do
    begin
    i := 0;
    while StringGrid1.Cells[i,z] <> '' do
      begin
      s := s + StringGrid1.Cells[i,z]+ #09;
      inc(i);
      end;
    AddTreeNodePathDupIgnore(TreeView1,s,#09,ReNode,AddSort);
    s := '';
    end;
  TreeView1.Items.EndUpdate;

DavidKlimas 3. Mai 2007 18:21

Re: StringGrid in Treeview zeigen
 
OK. Danke für den Tip. So bin ich fast am Ziel. Die Daten werden vom StringGrid ins Treeview übernommen und zusammengefasst :

Delphi-Quellcode:
function AddTreeNodePathDupIgnore(TV: TTreeView;
                                  Path: String;
                                  Delimiter: Char;
                                  var ReNode : TTreeNode;
                                  AddType: TAddType): Boolean;
var sL : TStringList;
    aNode : TTreeNode;
    z,iCount,zz,i : Integer;
begin
  Result := False;
  aNode := nil;
  ReNode := nil;
  sL := TStringList.Create;
  try
    //alle Delimiter durch #13 (carriage return [CR]) ersetzen
    for z := 1 to Length(Path) do
      if Path[z] = Delimiter then
        Path[z] := #13;

 
    //interner Parser der Stringlist teilt Path in Path-Token auf
    sL.Text := Path;

 
    //durch eventuelle doppelte oder abschließende Delimiter
    //erzeugte Leeritems in StringList löschen
    for z := sL.Count-1 downto 0 do
      if sL[z] = '' then
        sL.Delete(z);

 
    iCount := Pred(sL.Count);
    if TV.Items.Count > 0 then//min 1 Knoten vorhanden
      aNode := TV.Items[0];//beim ersten Knoten beginnen
 
    for z := 0 to iCount do//alle Token der StringList im TreeView suchen
    begin
      //solange noch Knoten in der Ebene vorhanden
      //und Knotentext ungleich gesuchten Token
      while Assigned(aNode) and (AnsiCompareStr(aNode.Text,sL[z]) <> 0) do
        aNode := aNode.GetNextSibling;//nächster Knoten
 
      if Assigned(aNode) then//Knoten gefunden
        //Funktions-Rückgabeparameter setzen
        ReNode := aNode
      else
      begin
        //Knoten nicht gefunden, also in TreeView einbauen
        Result := True;//Funktions-Rückgabewert setzen
        if assigned(ReNode) then//min Root wurde gefunden
          aNode := ReNode;//ausgehend vom letzten gefundenen Knoten
        case AddType of
        //alle nicht gefundenen Path-Token als Child einfügen
          AddTop :
            for zz := z to iCount do
              aNode := TV.Items.AddChildFirst(aNode,sL[zz]);
            //alle nicht gefundenen Path-Token einsortieren
          AddSort :
            begin
              for zz := z to iCount do
                if TV.Items.Count = 0 then//TreeView ist noch leer
                  aNode := TV.Items.AddChild(aNode,sL[zz])
                else
                  begin
                    if not (assigned(aNode)) then//in Root-Nodes suchen
                    begin
                      aNode := TV.Items[0];
                      while Assigned(aNode) and (AnsiCompareStr(aNode.Text,sL[zz]) < 0) do
                        aNode := aNode.GetNextSibling;

 
                      if Assigned(aNode) then//Einfügestelle gefunden
                        aNode := TV.Items.Insert(aNode,sL[zz])
                      else//nicht gefunden, also anhängen
                        aNode := TV.Items.AddChild(aNode,sL[zz]);
                    end
                    else//in weiteren Ebenen(Level) suchen
                    begin
                      if aNode.Count > 0 then//nur suchen wenn Child-Node vorhanden sind
                      begin
                        i := aNode.Count-1;
                        aNode := aNode[0];//auf ersten Child-Node setzen
                        while (aNode.Index < i) and (AnsiCompareStr(aNode.Text,sL[zz]) < 0) do
                          aNode := aNode.GetNextSibling;

 
                        if AnsiCompareStr(aNode.Text,sL[zz]) < 0 then
                          //Einfügestelle nicht gefunden
                          aNode := TV.Items.Add(aNode,sL[zz])
                        else
                          //Einfügestelle gefunden
                          aNode := TV.Items.Insert(aNode,sL[zz]);
                      end
                      else//kein Child-Node vorhanden
                        aNode := TV.Items.AddChild(aNode,sL[zz]);
                    end;
                  end;
            end;
            //alle nicht gefundenen Path-Token als Child anfügen
          AddBottom :
            for zz := z to iCount do
              aNode := TV.Items.AddChild(aNode,sL[zz]);
        end;{case} 

 
        ReNode := aNode;//Funktions-Rückgabeparameter setzen
        Break;//beenden der Path-Token-Such-Schleife
      end;{else} 

 
      if z < iCount then//beim letzten Path-Token nicht
        aNode := aNode.GetFirstChild;
    end;{for} 
  finally
    sL.Free;
  end;
end;
ABER, wie immer ein aber, der letzte eintrag soll etwas gesondert behandelt werden. z.B:

münchen
...Nürnberg
......würzburg <------Hier als Durchfahrtsbahnhof
.........Frankfurt
......Würzburg <------Hier als Endstation
Berlin
...Hannover <------Hier als Durchfahrtsbahnhof
......Düsseldorf
.........Saarbrücken
...Hannover <------Hier als Endstation
Hamburg
usw.

Die Einträge "Würzburg" und "Hannover" sollen zweimal im Tree erscheinen. Einmal als Endstation, einmal als Durchfahrt. Ich hab versucht, in der oberen prozedure rumzubasteln aber bekamm nicht das gewünchte ergebniss raus...

Lannes 3. Mai 2007 19:02

Re: StringGrid in Treeview zeigen
 
Hallo,

ob ich das richtig verstanden habe :gruebel:
Teste mal folgendes:
-der Funktion AddTreeNodePathDupIgnore den letzten Eintrag nicht mit übergeben
-die Funktion liefert Dir im Parameter ReNode den eingefügten bzw. gefundenen Knoten
-an diesen hängst Du dann Deinen letzten Eintrag aus der Row des Grids
Delphi-Quellcode:
//...
  TreeView.Items.AddChild(ReNode,DerLetzteAusDemGrid);
//...
Funkioniert nicht?
Eventuell mal Beispiel-Daten aus dem Grid und die beispielhafte Umsetzung als Tree dazu hier posten damit man Dein Vorhaben besser verstehen kann.

DavidKlimas 3. Mai 2007 19:08

Re: StringGrid in Treeview zeigen
 
Du hast es richtig verstanden. Leider ist das program ziemlich komplex und das StringGrid hat mehrere Tausend einträge, deswegen muss ich hier improvisieren, was manchmal recht unverständlich ist. Ich dachte daran, den letzten eintrag einfach abzuhängen und später einfach dazuzunehmen... Werd das mal probieren...

DavidKlimas 3. Mai 2007 19:32

Re: StringGrid in Treeview zeigen
 
Liste der Anhänge anzeigen (Anzahl: 3)
Hier ist das Beispiel :

Bin für hilfe dankbar...

DavidKlimas 3. Mai 2007 20:59

Re: StringGrid in Treeview zeigen
 
OK. Ich habs. Wie schon vorgeschlagen, wird der letzte eintrag wird immer seperat behandelt...

Lannes 3. Mai 2007 21:42

Re: StringGrid in Treeview zeigen
 
Hallo,
Zitat:

Zitat von DavidKlimas
...das StringGrid hat mehrere Tausend einträge...

falls du meine vorgeschlagene Vorgehensweise mit der Funktion genommen hast würde ich das bei einer so hohen Zeilenanzahl noch optimieren.

StringGrid.Rows ist vom Typ TStrings, der vor der Übergabe an die Funktion zu einen String zusammengesetzt wird, dieser String wird dann innerhalb der Funktion wieder aufgedröselt.
Änder doch die Funktion so ab das StringGrid.Rows direkt übergeben werden kann.
Außerdem könnte "case AddType of..." aus der Funktion überflüssig sein.

DavidKlimas 4. Mai 2007 11:31

Re: StringGrid in Treeview zeigen
 
Da ich in den ersten zwei spalten jeder zeile andere Infos hab, Hab ich die Rows-Funktion schon rausgenommen. Die AddType hab ich mitlerweile auch rausgenommen, trotzdem braucht das programm ne viertel stunde zum laden...

Ansonsten läufts super...

Lannes 4. Mai 2007 18:11

Re: StringGrid in Treeview zeigen
 
Hallo,

ein viertel Stunde, das dauert eindeutig zu lange. :shock:
Wieviel Einträge sind es denn 1000, 2000 oder eher 100000?

Werden BeginUpdate und EndUpdate in Deinem Code genutzt?
Wie sieht denn jetzt die abgespeckte Version der Funktion und deren Aufruf aus?

Wenn man da nichts mehr verbessern kann bietet es sich an nur die erste Ebene der Nodes bei der Initialisierung in das TreeView zu laden und die weiteren Ebenen erst auf Anforderung, also wenn der User einen Node expandiert.

Zip doch mal die Daten aus dem StringGrid(am besten als csv oder ähnlich) sowie Deinen aktuellen Code und poste sie hier, dann kann man auf der Grundlage eventuell einen performanteren Vorschlag machen.

DavidKlimas 4. Mai 2007 18:24

Re: StringGrid in Treeview zeigen
 
weiter oben hatte ich das programm schon als download eingetragen. Ist jedoch nicht mehr auf den neusten stand. Im StringGrid sind 350 zeilen zu 62 spalten (ungefähr). Jede zelle gib einen Index aus der in einer Datenbank mit 2700 zeilen ausgesucht werden muss...

DavidKlimas 5. Mai 2007 09:01

Re: StringGrid in Treeview zeigen
 
Liste der Anhänge anzeigen (Anzahl: 2)
Die Daten im StringGrid sind die Selben wie in der beigefügten Datenbenk (lines). Jeder Eintrag aus der Datenbank "Lines" ist ein Index, dessen StringWert in der 2.Datenbank "City" (Passwort = HausBau) gesucht werden muss. Im StringGrid sind demnach anstelle der Index-Werte die StringWerte.

Lannes 5. Mai 2007 22:45

Re: StringGrid in Treeview zeigen
 
Hallo,

Zitat:

Zitat von Lannes
Zip doch mal die Daten aus dem StringGrid(am besten als csv oder ähnlich) sowie Deinen aktuellen Code und poste sie hier, dann kann man auf der Grundlage eventuell einen performanteren Vorschlag machen.

hab mal deinen älteren Code überflogen.
Da werden Daten aus der Datenbank in ein verborgenes StringGrid geschrieben um sie dann an ein TreeView zu übergeben :gruebel:
>> siehe Kommentar
Delphi-Quellcode:
  TreeView1.Items.BeginUpdate;//vor der Schleife = ok
  TreeView1.Items.Clear;
  for z := 0 to DKStringGrid4.RowCount - 2 do
  begin
    If StrToInt(DKStringGrid4.Cells[0,z]) = ComboBox1.ItemIndex+ 1 then
    begin
      i := 2;
      For i := 2 to StrToInt(DKStringGrid4.Cells[1,z])+1 do
      begin
        CityTable.Locate('Index', DKStringGrid4.Cells[i,z] ,[]);
        Str1 := CityTable.FieldByName('City').AsString;
        Str1 := Str1 +' ('+CityTable.FieldByName('Station').AsString+')';
        s := s + Str1+ #09;
        Application.ProcessMessages;  //imho überflüssig    
      end;
      AddTreeNodePathDupIgnore(TreeView1,s,#09,ReNode,AddSort);
      s := '';
      TreeView1.Items.EndUpdate;  //Innerhalb der Schleife ??? 
      Application.ProcessMessages; //imho überflüssig
    end;
  end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:06 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz