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 Virtual Treeview - Nodes durch-iterieren - Wie? (https://www.delphipraxis.net/130536-virtual-treeview-nodes-durch-iterieren-wie.html)

torud 10. Mär 2009 07:44


Virtual Treeview - Nodes durch-iterieren - Wie?
 
Hallo Wissende,

ich habe eine kleine function, die von einem normalen Treeview auf einen virtual Treeview adaptieren will, finde aber keine Möglichkeit die Schleife so anzupassen, dass ich durch alle Nodes gehen kann und das Level prüfen und vergleichen kann.

Irgendwie ist das völlig anders beim VST. Hier mal das Original, wie es mit einem normalen Trreview funktioniert hat.

Delphi-Quellcode:
function GetItemsOfLevel(int_level_count : integer) : integer;
var
  i : integer;
begin
  Result := 0;
  with form1.tree do
    begin
      for i := 0 to Items.Count-1 do
        begin
          if Items.Item[i].Level = int_level_count then  inc(Result);
        end;
    end;
end;
Kann mir bitte jemand einen Tipp geben?

torud 10. Mär 2009 07:58

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Ich habs jetzt so gemacht, aber ich bin mir nicht sicher, ob das so in Ordnung ist.

Delphi-Quellcode:
function GetItemsOfLevel(int_level_count : integer) : integer;
var
  akt_Node, last_Node: PVirtualNode;
begin
  Result := 0;
  with form2.vst do
    begin
      akt_Node := GetFirst;
      last_Node := GetLast(nil);
      while not(akt_Node = last_Node) do
        begin
          if GetNodeLevel(akt_Node) = int_level_count then inc(Result);
          akt_Node := GetNext(akt_Node);
        end;
    end;
end;

hoika 10. Mär 2009 08:02

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Hallo,

benutze die CallBack-Funktion (hier im Tutorial beschrieben).


Heiko

torud 10. Mär 2009 08:25

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Hm, danke für die Antwort, aber das was ich fand, war nicht wirklich erschöpfend.

Ich geh mal davon aus, dass Du die CopySubTree-Routine gemeint hast und mir durch die Blume sagen wolltest, dass ich den Spass rekursiv durchlaufen soll...!?

Gruber_Hans_12345 10. Mär 2009 08:40

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
brauchst nicht den lastnode prüfen (den du bei deiner version auch übersehen würdest)

GetNext liefert eh nil zurück, wenn es keinen mehr gibt

Delphi-Quellcode:
function GetItemsOfLevel(int_level_count : integer) : integer;
var
  akt_Node: PVirtualNode;
begin
  Result := 0;
  with form2.vst do
    begin
      akt_Node := GetFirst;
      while assigned(akt_Node) do
        begin
          if GetNodeLevel(akt_Node) = int_level_count then inc(Result);
          akt_Node := GetNext(akt_Node);
        end;
    end;
end;

generic 10. Mär 2009 08:45

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Zitat:

Zitat von torud
Ich geh mal davon aus, dass Du die CopySubTree-Routine gemeint hast und mir durch die Blume sagen wolltest, dass ich den Spass rekursiv durchlaufen soll...!?

IterateSubTree meinte er.

hoika 10. Mär 2009 08:47

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Hallo,

eine CallBack-Funkon wird vom TreeView für alle Nodes durchlaufen.
Da gibt es kein "rekursiv".

die CallBack-Methode

Delphi-Quellcode:
 procedure LV_TPData_SearchCallBack(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Data: Pointer; var bAbort: Boolean);
und der Aufruf (ich suche ab Root, deshalb NIL).
Wird bAbort nicht angetastet, wird jeder Node übergeben.

Delphi-Quellcode:
  SearchTPItem.Id:= theId2Search;
    LV_TPData.IterateSubTree(NIL, LV_TPData_SearchCallBack, SearchTPItem);
SearchTPItem ist mein Data-Pointer (ich weise Objekte, nicht Records zu, aber nur am Rande).
Du du nicht suchst, kannst da das auf NIL setzen.


Heiko

torud 10. Mär 2009 09:25

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Liste der Anhänge anzeigen (Anzahl: 2)
Vielen Dank für Eure Geduld, aber ich quähl mich nun schon fast 2 Wochen mit dem Problem den Treeview inhaltlich um 90° gedreht zu visualisieren. So wie er ist habe ich das ja schon hinbekommen, aber nicht gedreht...

Ich hänge mal ein Bild dessen an, was ich bisher habe...baum.png
Und eins, wie ich es gern hätte, aber ich bekomms einfach nicht, da ich mit Rekursion und CallBacks noch nie so recht klargekommen bin.

Vielleicht habt ihr ja eine Idee? Ich zeig auch gern mal den Code, den ich bisher hatte, wenns sein muss. Ist eh nicht so dolle...

hoika 10. Mär 2009 09:54

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Hallo,

unwahrscheinlich, dass der VST das kann.
Zeig doch mal, wie es bisher aussieht ?
Oder ist das das 2. Bild ?


Heiko

generic 10. Mär 2009 10:14

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Eigentlich gilt hier im Forum: Neue Frage = neuer Post!

Bild 1 ist nicht möglich, würde ich selbst malen.
Bild 2 ist möglich über die Paint Ereignisse.

torud 11. Mär 2009 09:20

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Zitat:

Zitat von hoika
Hallo,
unwahrscheinlich, dass der VST das kann.
Zeig doch mal, wie es bisher aussieht ?
Oder ist das das 2. Bild ?
Heiko

Also das Bild baum.png ist das, was ich bisher schon realisiert habe. Das Ganze habe ich optional schon links- und rechtsbündig...
Das was Du auf dem Bild sehen kannst, sind einfach Panels.

Bei der Umsetzung der anderen Struktur, wie sie gern in Organigrammen benutzt wird, hakt es allerdings noch gewaltig. Das Problem ist eben einfach, dass jedes Kind, welches wieder eigene Kinder hat seinen eigenen visuellen Bereich markieren muss. Ich versuch das mal in einem kommenden Bild klarzumachen.


Zitat:

Zitat von generic
Eigentlich gilt hier im Forum: Neue Frage = neuer Post!
Bild 1 ist nicht möglich, würde ich selbst malen.
Bild 2 ist möglich über die Paint Ereignisse.

Ja, ich verspreche hiermit hoch und heilig, dass ich mich das nächste mal dran halte. Ich hatte die Organigramm vor 2 Wochen in einem anderen Forum gestellt und 0 Antworten erhalten. Jetzt habe ich hier mal Feedback. Das will ich mir mit nem neuen Post nicht kaput machen, denn ich brauche Hilfe, da ich bei LOGISCHEN Dingen nicht so der Burner bin.

Hier mal der aktuelle Code zum Generieren. Ich habe den Code aus der hier angebotenen Routine ForceTreeToList umgebaut. Nicht schön, aber es funktioniert.

Sicher ist das schon etwas zu viel. Wenn erwünscht, stelle ich auch gern mal die aktuelle EXE ein, damit man sich selbst ein Bild machen kann. Ich werde jetzt noch ein Bild erzeugen und später anhängen, welche die Probleme besser verständlich visualiseren soll. Vielen Dank schon vorab.

Delphi-Quellcode:
//diese procedure wird jedes mal ausgelöst, wenn man was am treeview macht...
procedure TForm1.CreateDiagram;
var
  //myButton : TButton;
  myButton : TAdvSmoothButton;
  i, k, int_obj_width, int_Top_offset, main_Left, int_Left_offset : integer;
  int_level_count, int_items_on_level : integer;
  myFirstNode, myHelpNode : PVirtualNode;
  akt_Node, last_Node: PVirtualNode;
  Data: PTreeData;
begin

  //löschen aller elemente auf der scrollbox
  while ScrollBox1.ControlCount > 0 do
    ScrollBox1.Controls[0].Free;

  //wenn struktur vertikal dann das hier
  //funzt schon sehr gut...
  case rad_type_struc.ItemIndex of
    0,1 : begin
              int_top    := 0;
              int_left   := 20;
              obj_counter := 0;
              Memo1.Clear;
              ForceTreeToList(nil, Memo1.Lines,-1);
              exit;
            end;
  end;

  //ansonsten struktur = horizontal
  [b]//ab hier haperts gewaltig[/b]
  int_obj_width  := 100;
  int_Top_offset := 20;
  int_Left_offset := 40;
  int_level_count := 0;
  main_Left      := 0;

  //sammeln der levels
  //diese routine zählt die max. leveltiefe in einem virtuellen treeview
  myFirstNode := form2.vst.GetFirst;
  myHelpNode := form2.vst.GetFirst;
  while not(form2.vst.GetLast(nil) = myHelpNode) do
    begin
      if form2.vst.GetNodeLevel(myHelpNode) > int_level_count then
        //counter hochzählen
        int_level_count := form2.vst.GetNodeLevel(myHelpNode);
      //helpnode auf nächste node verweisen
      myHelpNode := form2.vst.GetNext(myHelpNode);
    end;

  with form2.vst do
    begin
      akt_Node := GetFirst;
      last_Node := GetLast(nil);
      while not(akt_Node = last_Node) do
        begin

              myButton := TAdvSmoothButton.Create(self);
              myButton.Parent := ScrollBox1;
              myButton.Top := (akt_node.Index * 65) + int_Top_offset;
              myButton.Height := 30;

              inc(main_Left);
              myButton.Width  := int_obj_width;
              int_items_on_level := GetItemsOfLevel(form2.vst.GetNodeLevel(akt_Node));
              myButton.Left := ((ScrollBox1.Width div int_items_on_level) * (main_Left div 10)) - (myButton.Width div 2) ;
              Data := GetNodeData(akt_Node);
              myButton.Caption := Data.FCaption;
              myButton.Visible := true;
              myButton.Appearance.Font.Color := FontDialog1.Font.Color;
              myButton.Appearance.Font.Size := FontDialog1.Font.Size;
              myButton.Appearance.Font.Style := FontDialog1.Font.Style;
              myButton.BevelColor := ColorBD.Color;
              myButton.Color  := ColorBG.Color;

          akt_Node := GetNext(akt_Node);
        end;
    end;
end;

//diese procedure ruft die erzeuger-routine CreateLable auf und übergibt ihr wichtige daten
procedure TForm1.ForceTreeToList(Tree:TTreeView; Lines:TStrings; Layers:Integer=-1);
const
  // Verschiedene Zeichen für die Darstellung definieren
  intLeft1 : integer = 60;
  intLeft2 : integer = 0;
  intLeft3 : integer = 40;
  intLeft4 : integer = 40;
  procedure ForceChilds(fNode:PVirtualNode; strSpace:String; fLayer:Integer);
  var
    fChild:PVirtualNode;
    Data: PTreeData;
  begin
    // Für jeden Knoten und dessen Unterknoten wird ein Eintrag in
    // die Liste geschrieben. Um dies rekursiv zu machen, ruft sich die
    // Funktion selber wieder auf wenn ein weiterer Knoten mit Unterknoten
    // gefunden wurde. Aber immer nur solange bis die Anzahl Layers erreicht
    // wurde.
    if (assigned(fNode)) and ((fLayer < Layers) or (Layers = -1)) then
    begin
      Inc(fLayer);
      if (Form2.vst.HasChildren[fnode]) then
      begin
        inc(obj_counter);
        Data:=form2.VST.GetNodeData(fNode);
        int_top := obj_counter * 40;
        case rad_type_struc.ItemIndex of
          0 : int_left:= (form2.vst.GetNodeLevel(fNode)+1) * 40;
          1 : int_left:= ScrollBox1.Width - ((form2.vst.GetNodeLevel(fNode)+1) * 40) - 100;
        end;
        CreateLabel(int_top, int_left,Data.FHeight, Data.FWidth, form2.vst.GetNodeLevel(fNode), Data.FCaption);

        case rad_type_struc.ItemIndex of
          0 : int_left:= int_left + intLeft3;
          1 : int_left:= ScrollBox1.Width - (int_left + intLeft3) - 100;
        end;
        fChild:=form2.vst.GetFirstChild(fnode);
        repeat
          ForceChilds(fChild,strSpace,fLayer);
          fchild:=form2.vst.GetNextSibling(fchild);
        until not assigned(fChild);

        case rad_type_struc.ItemIndex of
          0 : int_left := intLeft1;
          1 : int_left := ScrollBox1.Width - intLeft1 - 100;
        end;
      end
      else
        begin
          inc(obj_counter);
          Data:=form2.VST.GetNodeData(fNode);
          int_top := obj_counter * 40;
          case rad_type_struc.ItemIndex of
            0 : int_left := (form2.vst.GetNodeLevel(fNode) + 1) * intLeft3;
            1 : int_left := ScrollBox1.Width - ((form2.vst.GetNodeLevel(fNode) + 1) * intLeft3) - 100;
          end;
          CreateLabel(int_top, int_left,Data.FHeight, Data.FWidth, form2.vst.GetNodeLevel(fNode), Data.FCaption);
        end;
    end;
  end;
var
  Node: PVirtualNode;
begin
  with form2.vst do
  begin
    BeginUpdate;
    Node := GetFirst;
    while Assigned(node) do
    begin
      ForceChilds(Node,'',0);
      Node := form2.vst.GetNextSibling(node);
    end;
    EndUpdate;
  end;
end;

//die bezeichnung ist nicht ganz korrekt, da kein label erstellt wird, sondern panels oder buttons
//die procedure selbst ruft abhängig vom gewählten style eine weitere unterprozedur auf zum erstellen des panels
//und erzeugt selbst dann noch ein paar shapes als verbinder zwischen den panels
procedure TForm1.CreateLabel(objTop, objLeft, objHeight, objWidth, objLevel : integer; objText:String);
var
  myShape : TShape;
begin
  //objText := objText + inttostr(obj_counter);
  case rad_type_button.ItemIndex of
    0 : CreateButtonWin(objTop, objLeft, objHeight, objWidth, objLevel,objText);
    1 : CreateButtonXP(objTop, objLeft, objHeight, objWidth, objLevel,objText);
    2 : CreateButtonGlas(objTop, objLeft, objHeight, objWidth, objLevel,objText);
    3 : CreateButtonGlow(objTop, objLeft, objHeight, objWidth, objLevel,objText);
  end;
      //erstelle lines zwischen controls
      if obj_counter > 1 then
        begin
          //horizontales shape
          myShape := TShape.Create(form1);
          myShape.Parent := ScrollBox1;
          myShape.Height := 1;
          myShape.Width := 20;
          case rad_type_struc.ItemIndex of
            0 : myShape.Left  := objLeft - 20;
            1 : myShape.Left  := objLeft + 100;
          end;
          myShape.Top   := objTop + 12;
          //vertikales shape
          myShape := TShape.Create(form1);
          myShape.Parent := ScrollBox1;
          myShape.Width := 1;
          case rad_type_struc.ItemIndex of
            0 : myShape.Left  := objLeft - 20;
            1 : myShape.Left  := objLeft + 120;
          end;
          if objLevel = 1 then
            begin
              myShape.Height := ((obj_counter-1) * 40) - 17;
              myShape.Top   := 70;
            end
          else
            begin
              myShape.Height := 22;
              myShape.Top   := objTop - 10
            end;
        end;
end;

//diese procedure erzeugt ein panel zur visualisierung eines treeview-items
procedure TForm1.CreateButtonWin(objTop, objLeft, objHeight, objWidth, objLevel : integer; objText:String);
var
  myButton : TPanel;
begin
  myButton := TPanel.Create(self);
  myButton.Parent := ScrollBox1;
  myButton.Top   := objTop;
  myButton.Left  := objLeft;
  myButton.Caption:= objText;
  myButton.Width := 100;
  myButton.Height := 30;
  myButton.Visible:= true;
  myButton.Font.Color := FontDialog1.Font.Color;
  myButton.Font.Size := FontDialog1.Font.Size;
  myButton.Font.Style := FontDialog1.Font.Style;
  myButton.Font.Name := FontDialog1.Font.Name;
  //myButton.BevelColor := ColorBD.Color;
  myButton.Color  := ColorBG.Color;
end;

hoika 11. Mär 2009 09:37

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Hallo

< Das Problem ist eben einfach, dass jedes Kind, welches wieder eigene Kinder hat seinen eigenen >
< visuellen Bereich markieren muss. Ich versuch das mal in einem kommenden Bild klarzumachen. >

wenn du das als Panel machst, sollte das doch gehen.

Unter-Diagramme landen als eigenständiges Panel
auf dem Panel des Eltern-Diagramms (Parent entsprechend setzen).

Die Panels kannst du übrigens durch folgenden Code direkt mit der Maus verschieben
(klappt bei meinem Form zumindestens).

Delphi-Quellcode:
procedure TPanel1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  ReleaseCapture;
  Perform(WM_SYSCOMMAND, SC_MOVE + 1, 2);
end;

Heiko

torud 11. Mär 2009 09:41

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Und zum besseren Verständnis hier das versprochene Bild mit einigen Kommentaren. Rechts im Bild seht Ihr den dazugehörenden Treeview. Ich will eigentlich "nur". das Generieren der Panels wie im vorangegangenen Thread automatisiert erledigen.

Da ich die Struktur des Treeviews nicht kennen kann, muss das Ganze logisch erfolgen und jedes Parent, welches Childs hat, müsste checken, wieviele Childs es hat und dann entsprechend der Anzahl genügend Raum für diese reservieren. Da kann man sicher auch hier und da was mit Offsets machen, aber wenn der Baum gewaltig in die Tiefe geht, könnts auch haarig werden. Ich habe noch keinen gangbaren Weg gefunden.

Kann mir von Euch jemand auf die Sprünge helfen - Bitte?

torud 11. Mär 2009 09:45

Re: Virtual Treeview - Nodes durch-iterieren - Wie?
 
Zitat:

Zitat von hoika
Hallo

< Das Problem ist eben einfach, dass jedes Kind, welches wieder eigene Kinder hat seinen eigenen >
< visuellen Bereich markieren muss. Ich versuch das mal in einem kommenden Bild klarzumachen. >

wenn du das als Panel machst, sollte das doch gehen.

Unter-Diagramme landen als eigenständiges Panel
auf dem Panel des Eltern-Diagramms (Parent entsprechend setzen).

Die Panels kannst du übrigens durch folgenden Code direkt mit der Maus verschieben
(klappt bei meinem Form zumindestens).

Delphi-Quellcode:
procedure TPanel1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  ReleaseCapture;
  Perform(WM_SYSCOMMAND, SC_MOVE + 1, 2);
end;

Heiko

Ich habe mal ein Bild im vorherigen Thread angehangen, welches zum Teil ganz gut verdeutlicht, wo die Krux liegt. Die erste Themengruppe hat kein Child, muss aber dennoch einen Platz reservieren, damit die Kinder der nächsten Gruppe nicht in ihr visuelles Revier eintauchen...

Das Verschieben der Panel ist schon drin, und soll eigentlich nur im Notfall zum Einsatz kommen. Aktuell habe ich leider noch keinen richtig funktionierenden Weg gefunden überhaupt die Positionen automatisiert hinzubekommen...für die horizontale Lösung...


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:08 Uhr.

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