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 VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText (https://www.delphipraxis.net/180561-virtualtreeview-bearbeitung-von-tvirtualnode-fuehrt-zum-abschneiden-von-nodetext.html)

Aviator 29. Mai 2014 15:02

VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText
 
Hallo Leute,

wie der Titel schon sagt, habe ich den Type
Delphi-Quellcode:
TVirtualNode = packed record
etwas verändert, da ich zu einer einzelnen Node noch gewisse zusätzliche Informationen benötige, um diese richtig zeichnen zu lassen. Mein Ziel ist es, dass ich pro Node und Column entscheiden kann, ob ein Image entweder zentriert oder linksbündig in die Zelle gemalt wird. Da das Malen des Bildes im Tree selbst geschehen soll und ich nur noch den "Status" der Bildposition übergeben möchte, wurde von mir eine Zeile
Delphi-Quellcode:
DrawImageCentered: Boolean;
zum TVirtualNode Record hinzugefügt. Des Weiteren habe ich den Type
Delphi-Quellcode:
TVirtualTreeColumn
um eine Property erweitert, um auch dort zu bestimmen, ob das Bild in der Mitte gemalt werden soll oder nicht.

Mein Problem ist nun folgendes: Sobald ich den TVirtualNode Record bearbeite (d.h. ein Feld/Variable hinzufüge), schneidet mir der Tree beim Zeichnen der Node einen Teil des Textes (meistens den letzten Buchstaben) ab und ersetzt diesen durch "..." (drei Punkte). Entferne ich die Änderung aus dem TVirtualNode Record ist alles wieder normal.

Im Record steht noch ein Hinweis, dass neue Felder (es ist also lt. Mike Lischke möglich neue Felder einzufügen) vor das Feld "Parent" gesetzt werden sollen. Das habe ich auch so gemacht, trotzdem tritt der beschriebene Fehler auf.

Ich hoffe es hat jemand einen Tipp für mich, wie ich diesen Fehler beheben kann. Wenn ich noch zusätzliche Informationen braucht, bin ich gerne bereit, euch diese zu geben, sofern ich diese besitze bzw. eine Antwort auf eure Frage habe.

Zwei Hinweise noch: Ich benutze die Version 5.2.0 des VST's und der Text wird in der Funktion
Delphi-Quellcode:
ShortenString
(bei mir Zeile 4799) gekürzt. Mein Problem ist nur, dass ich nicht weiß wieso.

Schonmal danke für die hoffentlich konstruktiven Antworten. :-D

nuclearping 29. Mai 2014 18:59

AW: VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText
 
Kann sein, dass ich nicht ganz hinter dein Problem steige, aber warum veränderst du denn überhaupt den Core-Typ TVirtualNode um zusätzliche Informationen zu speichern?

Der VirtualTreeView zeichnet sich doch gerade dadurch aus, dass du durch seine virtuelle Daten- und Knotenstruktur alles mögliche an Informationen zu einem Knoten speichern kannst.

In deinem Fall würde es genügen, einen Datentyp für die Knotendaten zu haben und dann das Bild selber zu zeichnen, wenn es über eine ImageList nicht so einfach geht. Zum Beispiel:
Delphi-Quellcode:
type
  TNodeData = record
    Image: TBitmap;
    Centered: Boolean;
  end;
  PNodeData = ^TNodeData;
 
// ...
VirtualStringTree1.NodeDataSize(SizeOf(TNodeData));

// ...
var
  Node: PVirtualNode;
  Data: PNodeData;
begin
  Node := VirtualStringTree1.AddChild(nil);
  Data := VirtualStringTree1.GetNodeData(Node);
  Data^.Image := TBitmap.Create; // In OnFreeNode wieder freigeben
  with Data^.Image do
    begin
      PixelFormat := pf24Bit;
      Width := 32;
      Height := 32;
      with Canvas do
        begin
          Brush.Color := clSkyBlue;
          Brush.Style := bsSolid;
          FillRect(ClipRect);
        end;
    end;
  Data^.Centered := TRUE; // FALSE ...
end;

procedure TForm1.VirtualStringTree1AfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
  Column: TColumnIndex; CellRect: TRect);
var
  X, Y: Integer;
  Data: PNodeData;
begin
  // Bild zB nur in die 2. Spalte zeichnen
  if Column <> 1 then
    Exit;

  Data := Sender.GetNodeData(Node);

  if Data^.Centered then
    begin
      X := ((CellRect.Left + CellRect.Right) div 2) - (Data^.Image.Width div 2);
      Y := ((CellRect.Top + CellRect.Bottom) div 2) - (Data^.Image.Height div 2);
    end
  else
    begin
      X := CellRect.Left; // + Margin ...
      Y := CellRect.Top; // + Margin ...
    end;

  TargetCanvas.Draw(X, Y, Data^.Image);
end;

Aviator 29. Mai 2014 19:24

AW: VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText
 
Hi nuclearping,

danke für deine Antwort. Klar könnte ich "von außen" das Bild selbst zeichnen. Ich dachte mir nur, dass ich das ganze Vorhaben direkt als grundlegende Funktion in den VST implementiere um die Funktion für alle neuen Projekte direkt zur Verfügung zu haben. Damit ich im Prinzip pro Column und pro Node (deshalb versuche ich auch den Record TVirtualNode zu bearbeiten) die Position des Bildes bestimmen kann (also im Prinzip pro Zelle), muss ich natürlich an diesen beiden Punkten eine Variable/ein Feld einfügen. In der Column hat es ohne Probleme funktioniert. Für das aktuelle Projekt würde mir das auch schon reichen. Nur würde ich es gerne etwas ausbauen und auch auf die einzelnen Nodes erweitern und nicht nur auf die gesamte Column.

Zur Info: Zum Zeichnen hätte ich auch eine ImageList zur Verfügung und könnte dann mittels
Delphi-Quellcode:
ImageList.Draw()
an die Position zeichnen.

Wichtiger Hinweis was mir noch aufgefallen ist: Die Eigenschaft toHotTrack des Trees ist aktiviert (TreeOptions). Sobald ich mit der Maus über eine Node fahre, bei der der Text abgeschnitten ist, wird der Text vollständig sichtbar. Das Problem taucht also nur beim ersten Mal (beim Erstellen) der Node auf. Danach ist der Text richtig. Mir ist aber auch noch aufgefallen, dass durch die Änderung des Records einige andere grundlegende Funktionen nicht mehr funktionieren.

Für weitere Vorschläge bin ich sehr dankbar.

jaenicke 29. Mai 2014 20:32

AW: VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText
 
Dann leite besser eine eigene Komponente davon ab... das haben wir auch gemacht. Solche Funktionen stehen nun direkt zur Verfügung, aber ohne am Quelltext der Komponente selbst etwas zu ändern. Durch eine Änderung des Quelltextes verlierst du die Möglichkeit auf neuere Versionen upzugraden, zudem musst du deine Änderungen in Quelltextform zur Verfügung stellen, wenn du ein damit erstelltest Programm veröffentlichst!

Um zusätzlich andere Nutzerdaten unterzubringen hängt an jedem Eintrag ein generischer Container, der beliebige Daten enthalten kann. Auf die kann man auch direkt generisch zugreifen.

Aviator 30. Mai 2014 13:59

AW: VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText
 
Danke für die Antwort. Das Programm wird von mir nicht veröffentlicht sondern lediglich privat genutzt. Von daher ist eine Publizierung des Quelltextes nicht notwendig (würde ich vermuten). Es wäre eine schöne Lösung, wenn ich es irgendwie hinbekommen könnte, dass der Record erweitert werden kann und trotzdem alle Funktionen nach wie vor vorhanden sind. Wenn es so nicht gehen sollte, muss ich es eben "von außen" angehen und das Bild selbst zeichnen.

jaenicke 30. Mai 2014 15:24

AW: VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText
 
Ich kann das Problem leider nicht reproduzieren (wobei ich natürlich die neueste Version 5.3 getestet habe). Kannst du vielleicht ein Beispielprojekt und den geänderten Record anhängen?

Hast du vielleicht Spalten definiert, so dass es an einer Spalte abgeschnitten wird oder so?

Aviator 30. Mai 2014 18:24

AW: VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText
 
Hallo zusammen.

Zitat:

Zitat von jaenicke (Beitrag 1260791)
Ich kann das Problem leider nicht reproduzieren (wobei ich natürlich die neueste Version 5.3 getestet habe). Kannst du vielleicht ein Beispielprojekt und den geänderten Record anhängen?

Der geänderte Record sieht folgendermaßen aus:
Delphi-Quellcode:
  TVirtualNode = packed record
    Index,                  // index of node with regard to its parent
    ChildCount: Cardinal;   // number of child nodes
    NodeHeight: Word;       // height in pixels
    States: TVirtualNodeStates; // states describing various properties of the node (expanded, initialized etc.)
    Align: Byte;            // line/button alignment
    CheckState: TCheckState; // indicates the current check state (e.g. checked, pressed etc.)
    CheckType: TCheckType;  // indicates which check type shall be used for this node
    Dummy: Byte;            // dummy value to fill DWORD boundary
    TotalCount,             // sum of this node, all of its child nodes and their child nodes etc.
    TotalHeight: Cardinal;  // height in pixels this node covers on screen including the height of all of its
                             // children

    DrawImageCentered: Boolean; // >>>>>>>>>> HIER MEINE ÄNDERUNG <<<<<<<<<<
   
    // Note: Some copy routines require that all pointers (as well as the data area) in a node are
    //       located at the end of the node! Hence if you want to add new member fields (except pointers to internal
    //       data) then put them before field Parent.
    Parent,                 // reference to the node's parent (for the root this contains the treeview)
    PrevSibling,            // link to the node's previous sibling or nil if it is the first node
    NextSibling,            // link to the node's next sibling or nil if it is the last node
    FirstChild,             // link to the node's first child...
    LastChild: PVirtualNode; // link to the node's last child...
    Data: record end;       // this is a placeholder, each node gets extra data determined by NodeDataSize
  end;
Ein Beispielprojekt ist schwierig. Ich habe versucht, ein neues Projekt zu erstellen, in dem nur die geringst mögliche Anzahl von Codezeilen vorhanden sein muss, damit man etwas sieht. Die Einstellungen des Trees habe ich ebenfalls übernommen.

Folgende Einstellungen sind geändert:
Code:
TreeOptions.AnimateOptions --> Beides aktiviert
TreeOptions.PaintOptions --> toUseExplorerTheme (aktiviert)
TreeOptions.MiscOptions --> toCheckSupport (aktiviert)
Allerdings schmiert mir das Projekt direkt ab, sobald ich eine Stringvariable im GetText Event in meinem Datenrecord anspreche. NodeDataSize ist gesetzt, daran sollte es also nicht liegen.

Mein Datenrecord bei dem das Programm den Müll verursacht, aber nicht abschmiert sieht folgendermaßen aus:
Delphi-Quellcode:
  TAttribs = record
    FAttribDBID : Int64;
    FAttribGroupDBID : Int64;
    FCaption : string;
    FGroupCaption : string;
    FDescription : string;
    FAttribChecked : Boolean;
  end;
  PAttribs = ^TAttribs;
Zitat:

Zitat von jaenicke (Beitrag 1260791)
Hast du vielleicht Spalten definiert, so dass es an einer Spalte abgeschnitten wird oder so?

Darauf kann ich dir ein klares "Nein" geben. Wäre zu schön gewesen und war auch das Erste, an das ich gedacht hatte, weil es bei dem Tree, bei dem ich es bemerkt hatte, kein Header sichtbar ist.

Das eigentliche Projekt kann ich nicht hochladen, da dort noch eine Datenbank und einige andere Dinge dahinterstecken und es auch relativ groß ist. Ich hoffe du/ihr könnt mit diesen Infos etwas anfangen.

jaenicke 1. Jun 2014 14:02

AW: VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Aviator (Beitrag 1260804)
Ein Beispielprojekt ist schwierig.

Ohne weiß ich leider nicht wie ich den Fehler bekomme.

Ich habe einmal als Beispiel angehängt wie ich es lösen würde. Statt der generischen Ableitung als Container wären natürlich auch abgeleitete Klassen möglich, aber so hat das den Vorteil, dass man beliebige Daten in den Knoten packen kann...

Aviator 1. Jun 2014 14:14

AW: VirtualTreeView - Bearbeitung von TVirtualNode führt zum Abschneiden von NodeText
 
Hi Sebastian. Danke für das Beispiel. Habe es mal kurz überflogen und schon einige Dinge gesehen, mit denen ich mich nicht so direkt (gar nicht?) auskenne. Bin eben nur ein Hobbyprogrammierer bzw. jemand, der es sich über einige Jahre selbst beigebracht hat.

Wenn ich das richtig sehe, dann hast du in dem Beispiel mit generischen Typen gearbeitet, oder? Kenne ich jetzt nur aus dem vor kurzem von "Der schöne Günther" geöffneten Thread. Damit muss ich mich mal beschäftigen. Die Philosophie ist mir zwar (so würde ich vermuten) bekannt, aber selber schreiben könnte ich so etwas wohl nicht.

Tut mir leid, dass ich kein Beispielprojekt zustande gebracht habe, bei dem dieser Fehler auftritt. Bei meinem aktuellen größeren Projekt tritt der Fehler immer auf und auch ohne, dass das Programm mit einer AV abstürzt. Bei dem Testprojekt war das direkt der Fall und ich weiß nicht wieso.

Trotzdem danke für das Beispiel und auch für deine Zeit. :thumb: Ich versuche mal, mich damit auseinanderzusetzen bzw. gebe mich vielleicht auch mit einer meiner zwei Änderungen zufrieden, in der ich zumindest pro Column entscheiden kann, wo das Bild gemalt werden soll.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:37 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