Treeview in Report zum Drucken darstellen

Rund um die LCL und andere Komponenten
Antworten
pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Treeview in Report zum Drucken darstellen

Beitrag von pschoett »

Hallo allerseits,
ich möchte einen Treeview zum Ausdrucken auf einem Report darstellen. Optimal wäre es, wenn es eine grafische Komponente gäbe, die einen TreeView zum Drucken bereitstellt. Gibt es sowas?

Da ich bei Lazarus nicht davon ausgehe, erkläre ich was ich im Detail möchte.

Die Daten für den Treeview stammen aus einer Tabelle, in der jeder Knoten als Datenzeile gespeichert wird. Die Tabelle hat verkürzt betrachtet folgende Felder:
  • keyA: eindeutige ID für jeden Knoten eines Baumes
  • parentkey: ID des Vaterknotens
  • ebene: Anzahl Vaterknoten bis zur Wurzel; die Wurzel hat ebene=0
Die Frage ist, wie kann ich anhand dieser Felder die Daten sortieren, so dass der Report Zeile für Zeile abarbeitet und die Knoten in der Reihenfolge des TreeViews darstellt. (Das Einrücken zur Darstellung der Ebenen ist erst einmal ein zweitrangiges Problem.)

Hat jemand eine Idee?

Gruß,
Peter

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 7323
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Treeview in Report zum Drucken darstellen

Beitrag von af0815 »

pschoett hat geschrieben:Die Daten für den Treeview stammen aus einer Tabelle, in der jeder Knoten als Datenzeile gespeichert wird.
Auf einem MsSQL Server würde ich das ganze mal mit T-SQL in eine Struktur bringen, das das ganze mit dem normalen Report ausgegeben werden kann. Da halte ich mich an die Vorschläge und Beispiele von Ken Henderson Transact-SQL. :mrgreen:
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Re: Treeview in Report zum Drucken darstellen

Beitrag von pschoett »

af0815 hat geschrieben:Auf einem MsSQL Server würde ich das ganze mal mit T-SQL in eine Struktur bringen, das das ganze mit dem normalen Report ausgegeben werden kann. Da halte ich mich an die Vorschläge und Beispiele von Ken Henderson Transact-SQL. :mrgreen:
Et ist MySQL und leider kenne ich das Buch von Ken Henderson nicht :(

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 7323
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Treeview in Report zum Drucken darstellen

Beitrag von af0815 »

pschoett hat geschrieben:Et ist MySQL und leider kenne ich das Buch von Ken Henderson nicht :(
Wenn du willst, kannst du mir deine Mailadr per PN schickst, dann kann ich dir die paar Seiten dazu scannen und senden.

Damit du dich entscheiden kannst ob du das Buch kaufst :mrgreen:

Andreas
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Re: Treeview in Report zum Drucken darstellen

Beitrag von pschoett »

Danke für den Hinweis auf Ken Henderson. Ich muss gestehen, ich habe nicht alles davon verstanden, so dass ich erstmal mit den Daten wie sie vor mir liegen arbeiten will.

Der fertige TreeView liegt mir vor, bevor ich den Report erstelle. Jetzt muss ich nur noch die Knoten durchwandern und dabei entweder in ein Hilfsfeld der Ursprungstabelle oder noch einfacher in eine temporäre MemoryTabelle schreiben. Auf eine der beiden Varianten kann sich dann der Report beziehen und das TreeView Satz für Satz aufbauen.

Ein TreeView kann beliebig viele Ebene haben und sieht zB so aus:

Code: Alles auswählen

0
 0.1
  0.1.2
   0.1.2.3
    0.1.2.3.4
  0.1.2.5
  0.1.2.6
  0.1.2.7
  0.1.2.8
 0.1.9
 0.1.10
 0.11
  0.11.12
  0.11.13
  0.11.14
 0.15
 0.16
 0.17
Folgende Voraussetzungen:
  • In der Praxis wird ein TreeView genau eine Wurzel haben und mind. ein Kind haben.
  • Jeder Knoten kennt das Hilfsfeld: Reihenfolge (Integer, default=0)
  • Jeder Knoten kennt das Hilfsfeld: AlleKinderBesucht (boolean, default=false)
Mein Code sieht so aus:

Code: Alles auswählen

 
procedure TForm1.btnCreateReport(Sender: TObject);
  procedure NumberNode(Node: TTreeNode; i: Integer);
  begin
    while Node.HasChildren And (TTeile(Node.Data).AlleKinderBesucht <> true) do
    begin
      TTeile(Node.Data).Reihenfolge:=i;
      inc(i);
      NumberNode(Node.GetFirstChild, i);
    end;
 
    while (Node.GetNextSibling <> nil) do
    begin
      If TTeile(Node.Data).AlleKinderBesucht <> true Then
      begin
        TTeile(Node.Data).Reihenfolge:=i;
        inc(i);
      end;
      NumberNode( Node.GetNextSibling, i);
    end;
 
    SchreibeNode(Node, i);
    If Node.HasChildren <> true Then
      TTeile(Node.Data).AlleKinderBesucht := true;
    inc(i);
 
    If (Node.Parent.AbsoluteIndex = TreeView2.Items.GetFirstNode.AbsoluteIndex) then
      exit
    else
    begin
      TTeile(Node.Parent.Data).AlleKinderBesucht := true;
      NumberNode(Node.Parent, i);
    end;
  end;
 
begin
  If TreeView2.Items.GetFirstNode <> nil then NumberNode( TreeView2.Items.GetFirstNode, 1);
end;
 
Das obige Beispiel eines Treeviews ist real und führt im Code dazu, dass die ersten 15 Knoten richtig gesetzt werden, dann aber eine Endlosschleife zwischen den beiden letzten Knoten 0.16 und 0.17 aufläuft.

Was mache ich falsch?

Gruß,
Peter

pschoett
Beiträge: 36
Registriert: Sa 7. Feb 2015, 11:48

Re: Treeview in Report zum Drucken darstellen

Beitrag von pschoett »

Nachdem ich so viel aufhebens um mein Problem(chen) gemacht habe, will ich auch die Lösung verraten, wie es für mich funktioniert.

Code: Alles auswählen

procedure TForm1.btnDruckenClick(Sender: TObject);
var
  k, j: integer;
 
  procedure SchreibeNode(Node: TTreeNode);
  begin
    Node.Text := IntToStr(j) + '   ' + Node.Text;
    TTeile(Node.Data).Reihenfolge := j;
    TTeile(Node.Data).Besucht := true;
    inc(j);
    Application.ProcessMessages;
  end;
 
  procedure NumberNode(Node: TTreeNode);
  begin
    inc(k); Label1.Caption := IntToStr(k); Application.ProcessMessages;
 
    If (Node.HasChildren And (TTeile(Node.Data).AlleKinderBesucht <> true)) Then
    begin
      If TTeile(Node.Data).Besucht <> true Then
        begin
          SchreibeNode(Node);
          If Node.HasChildren <> true Then TTeile(Node.Data).AlleKinderBesucht := true;
        end;
      NumberNode(Node.GetFirstChild);
    end;
 
    If (TTeile(Node.Data).AlleKinderBesucht
    And (TTeile(Node.Data).keyA = TTeile(TreeView2.Items.GetFirstNode.Data).keyA)) then
      exit;
 
    If (Node.GetNextSibling <> nil) Then
    begin
      If TTeile(Node.Data).AlleKinderBesucht <> true Then
        If TTeile(Node.Data).Besucht <> true Then
          begin
            SchreibeNode(Node);
            If Node.HasChildren <> true Then TTeile(Node.Data).AlleKinderBesucht := true;
          end;
      NumberNode( Node.GetNextSibling);
    end;
 
    If (TTeile(Node.Data).AlleKinderBesucht
    And (TTeile(Node.Data).keyA = TTeile(TreeView2.Items.GetFirstNode.Data).keyA)) then
      exit;
 
    If TTeile(Node.Data).Besucht <> true Then
      begin
        SchreibeNode(Node);
        If Node.HasChildren <> true Then TTeile(Node.Data).AlleKinderBesucht := true;
      end;
 
    TTeile(Node.Parent.Data).AlleKinderBesucht := true;
    If (TTeile(Node.Parent.Data).keyA = TTeile(TreeView2.Items.GetFirstNode.Data).keyA) then
      exit
    else
      NumberNode(Node.Parent);
 
  end;
 
begin
  for j := 0 to TreeView2.Items.Count -1 do  // zurücksetzen der Knoten
  begin
    TTeile(TreeView2.Items[j].Data).Reihenfolge := 0;
    TTeile(TreeView2.Items[j].Data).AlleKinderBesucht := false;
    TTeile(TreeView2.Items[j].Data).Besucht := false;
  end;
 
  j := 1;
  k := 0;   // Hilfsvariable, kann gelöscht werden, wenn fertig
  If TreeView2.Items.GetFirstNode <> nil then
    NumberNode( TreeView2.Items.GetFirstNode);
end;
Allerdings ist der Code nicht wirklich effizient. Ich lasse mir mit der Hilfsvariable k die Aufrufe der procedure NumberNode anzeigen, dabei ist k=230 für das Beispiel mit 17 Knoten, das ich weiter oben beschrieben habe. Optimal ist anders, aber ich bin erst einmal zufrieden, dass ich das überhaupt hinbekommen habe.

Antworten