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 Das verrückte Formular (https://www.delphipraxis.net/181508-das-verrueckte-formular.html)

Tenobaal 21. Aug 2014 10:08

Das verrückte Formular
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo! Ich möchte ein Formular im Clientbereich einer TPanel-Komponente einblenden. Soweit kein Problem, habe ich schon tausend mal gemacht. Es funktioniert auch, allerdings verhält sich das Formular im Clientbereich des Panels dann nicht wie erwartet. Wenn ich das Formular im eigenständigen Fenster erzeuge, funktioniert es jedoch wie es soll.

Ich gebe mal einen kurzen Überblick über den Quellcode des Projekts, den ich auf das wesentliche reduziert habe:

Formular TForm1
  • Hauptformular zur Demonstration des Programms.
  • Hat eine TPanel Komponente auf dessen Clientbereich das Formular "TFormCreateGeometry" eingeblendet werden soll, wenn der Button "Erzeuge im Panel" gedrückt wird.
  • Der Button "Erzeuge im Fenster" erzeugt das Formular "TFormCreateGeometry" als eigenständiges Fenster.

Formular TFormCreateGeometry
  • Das Formular "TFormCreateGeometry" enthält eine TTreeView Komponente. Im OnCreate-Event des Formulars werden die 5 Knoten Rootnode, LinesNode, PointsNode, AreasNode, MatNode erstellt und dem TreeView hinzugefügt.
  • Der Button "btnAddPoints" soll dem Knoten "PointsNode" zur Laufzeit des Programms weitere Kindknoten hinzufügen.

Problembeschreibung:
Wird das Formular "TFormCreateGeometry" im Clientbereich des Panels erstellt, dann werden die Kindknoten nach betätigen des Buttons "btnAddPoints" nicht dem Knoten "PointsNode" sondern dem Knoten "LinesNode" hinzugefügt.
Wenn das Formular "ganz normal" im eigenständigen Fenster erstellt wird, dann werden die Kindknoten wie erwartet dem Knoten "PointsNode" angehangen.
Ich suche schon seit zwei Tagen nach dem Fehler und bin keinen Schritt weiter gekommen. Ich habe auch schon ein neues Projekt angelegt, um auszuschließen das die Entwicklungsumgebung (RAD Studio XE5) etwas an den Dateien manipuliert hat, was im Quellcode nicht sichtbar ist.

jaenicke 21. Aug 2014 10:42

AW: Das verrückte Formular
 
Liste der Anhänge anzeigen (Anzahl: 1)
Erklären kann ich das auch nicht ohne genauer zu debuggen, aber es wird wohl daran liegen, dass das Formular so ein zweites Mal angezeigt wird und dabei evtl. irgendwelche Handles neu erzeugt werden. Dadurch zeigen dann die Knoten auf den falschen Zielknoten wie du beim Debuggen sehen kannst (einfach Maus über PointsNode halten, wenn du in der Zeile bist, in der die Punkte hinzugefügt werden).

Aufgrund solcher und anderer Probleme, insbesondere was die Langsamkeit und die fehlende Anpassbarkeit angeht, nutze ich auch ausschließlich die Virtual Trees.

Nichtsdestotrotz ist es ohnehin keine gute Idee im Konstruktor mehr zu machen als Klassen zu erzeugen usw., so dass die funktionierende Lösung im Anhang ohnehin die sauberere Lösung ist. Und zwar einfach eine separate Methode zur Initialisierung benutzen.

Dejan Vu 21. Aug 2014 10:43

AW: Das verrückte Formular
 
-Blödsinn-

Uwe Raabe 21. Aug 2014 11:00

AW: Das verrückte Formular
 
Duch das Setzen von
Delphi-Quellcode:
Form.Parent := pnl1;
wird ein DestroyHandle aufgerufen, was intern dazu führt, daß die Items des TreeView freigegeben und neu erzeugt werden. Dadurch werden die gespeicherten Pointer auf die TreeNodes ungültig.

Eventuell kannst du das Anlegen der Nodes in eine separate Methode verlagern, die du nach dem Setzen des Parent nochmal aufrufst.

himitsu 21. Aug 2014 11:05

AW: Das verrückte Formular
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1269358)
Duch das Setzen von
Delphi-Quellcode:
Form.Parent := pnl1;
wird ein DestroyHandle aufgerufen, was intern dazu führt, daß die Items des TreeView freigegeben und neu erzeugt werden. Dadurch werden die gespeicherten Pointer auf die TreeNodes ungültig.

Es kommt immer darauf an, wie das intern behandelt wird.

Wenn nur die Handles freigegeben werden, dann bleiben meistens dennoch die TObjekt-Klassen erhalten und danach wird dann daraus/darin dann wieder das neue Handle erzeugt.
Aber wie der TreeView intern mit seinen Items umgeht, weiß ich jetzt auch nicht.

Das kann man aber leicht prüfen.
> Einfach vor dem AddChild nochmal den "aktuellen" Wert auslesen, also das Item suchen, und dann die Zeiger vergleichen.

Natürlich kann man auch einfach immer den Parent jedesmal über den Namen neu suchen, beim Add, und auf diese globalen Variablen verzichten, vorallem wenn mann jetzt weiß (vermutlich), daß es mit diesen Zeigern gern Probleme gibt und sie sich schnell mal ändern könnten.

Uwe Raabe 21. Aug 2014 11:18

AW: Das verrückte Formular
 
Zitat:

Zitat von himitsu (Beitrag 1269361)
Zitat:

Zitat von Uwe Raabe (Beitrag 1269358)
Duch das Setzen von
Delphi-Quellcode:
Form.Parent := pnl1;
wird ein DestroyHandle aufgerufen, was intern dazu führt, daß die Items des TreeView freigegeben und neu erzeugt werden. Dadurch werden die gespeicherten Pointer auf die TreeNodes ungültig.

Es kommt immer darauf an, wie das intern behandelt wird.

In TCustomTreeView.DestroyWnd wird der Inhalt von Items in einen MemoryStream geschrieben und Items.Clear aufgerufen. In dem Moment sind die TreeNode-Pointer schon ungültig, obwohl sie noch die richtigen Daten enthalten. Nach dem Recreate werden die TTreeNodes zwar wieder hergestellt, allerdings stimmt die Position im Speicher mit hoher Wahrscheinlichkeit nicht mehr mit der vorigen überein. Das dauerhafte Speichern von Pointern auf TreeNodes ist also mit Vorsicht zu genießen. Leider gibt es auch keinen brauchbaren Event, mit dem man das abfangen könnte.

himitsu 21. Aug 2014 11:20

AW: Das verrückte Formular
 
PS: Wenn sich die Zeiger geändert haben, dann ist es doch ein großer Zufall, daß die neue Instanz zufällig auf der Adresse der alten Instanz des anderen Knoten liegt. :stupid:


brauchbarer Event: TreeView ableiten, die "CreateWnd"-Methode überschreiben und sein eigenes Event implementieren,
bzw. die Methode, welche den Nodes aus'm Stream läd.

Tenobaal 21. Aug 2014 11:25

AW: Das verrückte Formular
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1269358)
Duch das Setzen von
Delphi-Quellcode:
Form.Parent := pnl1;
wird ein DestroyHandle aufgerufen, was intern dazu führt, daß die Items des TreeView freigegeben und neu erzeugt werden. Dadurch werden die gespeicherten Pointer auf die TreeNodes ungültig.

Eventuell kannst du das Anlegen der Nodes in eine separate Methode verlagern, die du nach dem Setzen des Parent nochmal aufrufst.

Mir war nicht bewusst, dass
Delphi-Quellcode:
Form.Parent := pnl1;
ein DestroyHandle aufruft. Beim Debuggen fiel mir auch auf, dass die zuvor angelegten TTreeNode-Objekte (Rootnode, LinesNode... etc.) falsche Objektadressen haben, nachdem das neue Parent gesetzt wurde. Das scheint eine Eigenart beim TreeView sein, denn bisher ist ein derartiges Problem noch nicht aufgetreten, obwohl ich ständig Formulare auf irgentwelche Panel setze.

Tausend Dank für eure Hilfe :thumb:

pertzschc 21. Aug 2014 11:47

AW: Das verrückte Formular
 
Zitat:

Zitat von Dejan Vu (Beitrag 1269353)
-Blödsinn-

???

himitsu 21. Aug 2014 11:50

AW: Das verrückte Formular
 
Gut, daß die Objektinstanzen bei sowas verschwinden, ist auch recht selten und passiert bei den meisten VCL-Klassen auch nicht.

Das dahinterliegende Windows-Handle kann aber schnell mal verschwinden und neu entstehen,
wobei dann gerne Dinge verloren gehn, die man im OnCreate oder im Contructor eingestellt hat, indem man die WinAPI nahm und es direkt im Handle erledigte.
(Drag&Drop aktivieren, EM_SETCUEBANNER, usw.)

Zitat:

Zitat von pertzschc (Beitrag 1269376)
???

Er hat seinen Beitrag schnell genug editiert, so daß die DP noch keine "editiert"-Meldung drunterschreibt.
Und das gelöscht, was vorher drin stand, welches er als unpassende/falsche Antwort empfand.


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