![]() |
Parent Problem
Hallo zusammen,
ich habe ein Problem wofür ich keine Lösung weiss. Ich habe eine eigene Komponente auf Basis eines Panels. Auf diesem liegt eine Combobox. Diese lege ich beim Erzeugen der Klasse an, und versuche die Items zu ändern. Ich erzeuge die Klasse in meinem Programm mit: x := TMyClass.Create(self); x.Parent := self; Leider bleibt er schon beim Create hängen und zwar beim Items.Clear der Combobox. Was muss ich nun tun? Muss ich das Parent nach dem Create auf Parent := TWinControl(AOwner) oder die Items.Clear später ausführen? Wenn ja, wann? Ich bin ein bisschen ratlos. Danke für eure Hilfe. Oliver |
Re: Parent Problem
Hi,
die Combobox arbeitet nicht so richtig rund ohne übergeordenetes Fenster. Du solltest also die Items immer nur dann verändern (egal wie), wenn Du die Combobox (oder die Hierachie von möglichen Parents) in einem Fenster liegt. In diesem Fall muss das Panel also auf einem Fenster platziert werden (bzw. ebend ein der Parent des Panel oder dessen Parent...). Gruß Der Unwissende |
Re: Parent Problem
Soweit hatte ich mir das schon gedacht.
Die Frage ist, ob es eine Funktion gibt die ich überladen kann, wenn das Parent zugewiesen wird. |
Re: Parent Problem
es wäre doch möglich über den ersten parameter ein owner zu übergeben (z.B. Form1)
Delphi-Quellcode:
x := TMyClass.Create(Form1);
with x do begin Parent := Form1; [...] end; x.Free; |
Re: Parent Problem
Zitat:
|
Re: Parent Problem
Am Besten Du überschreibst einfach die Parent-Property deiner Klasse (TMyClass). Denn wenn Du dann deinen Parent lädst, kannst Du (im Setter deiner eigenen Parent-Property) schon eine Zeile darunter ohne weitere Probs die Items deiner ComboBox clearen:
Delphi-Quellcode:
TMyClass = class(TPanel)
AComboBox : TComboBox; constructor Create(AOwner : TComponent); override; private function getAParent : TWinControl; procedure setAParent(AParent: TWinControl); public property Parent read getAParent write setAParent; end; . . function TMyClass.getAParent : TWinControl; begin Result := inherited Parent; end; procedure TMyClass.setAParent(AParent : TWinControl); var lastParent : TWinControl; begin lastParent := inherited Parent; inherited Parent := AParent; if lastParent = nil then // nur beim aller ersten Parent-Laden AComboBox.Items.Clear; end; edit: minimale Schönheitskorrektur am Code |
Re: Parent Problem
Ich verstehe wohl das Problem nicht .... :roll:
Du hast eine Klasse TMyClass, die aus einem Panel mit einer ComboBox darauf besteht. Dann solltest du auch alle notwendigen Schritte der Erstellung im Konstruktor deiner Klasse vornehmen.
Delphi-Quellcode:
Dann kannst du anschließend also nach dem X:=TMyClass.Create(Form1); im Hauptteil des Programms tun und lassen was du möchtest.
constructor TMyClass.Create(Compo:TComponent);
begin inherited; parent:=TWinControl(Compo); combo:=TCombobox.Create(self); combo.Parent:=self; end; |
Re: Parent Problem
Der Owner des Objektes muss aber nicht zwingend auch sein Parent sein. Gut vorstellbar wäre z.B. auch die Situation bei der dieses Panel-ComboBox-Objekt selbst wieder auf einem anderen Panel Platz mehmen soll...
|
Re: Parent Problem
Zitat:
Zitat:
Ebensogut könnte man nach dem Erzeugen den Parent verbiegen:
Delphi-Quellcode:
Oder man könnte im Konstruktor den Parent fest einbrennen:
X:=TMyClass.Create(Form1);
X.Parent:=Panel2:
Delphi-Quellcode:
Als letztes könnte man auch einen Parent getrennt mit übergeben (so würde ich es wahrscheinlich machen):
constructor TMyClass.Create(Compo:TComponent);
begin inherited; parent:=Panel2; combo:=TCombobox.Create(self); combo.Parent:=self; end;
Delphi-Quellcode:
Wichtig für sein Problem ist nur, dass die Eigenschaft Parent direkt beim Erzeugen belegt wird. Mehr wollte ich nicht ausdrücken.
X:=TMyClass.Create(Form1, Panel2);
............... constructor TMyClass.Create(Compo:TComponent; WinC: TWinControl); begin inherited create(Compo); parent:=WinC; combo:=TCombobox.Create(self); combo.Parent:=self; end; |
Re: Parent Problem
Zitat:
Das Problem (das Du nach eigener Aussage nicht verstehst) für das Du hier eine Lösung anbietest ist nicht das, das der Thread-Steller hat. Wie vorhin schon gesagt wurde, wird ein Fenster in der Hierachie der Parents benötigt. Probier es einfach mal aus, erstell Dir dyn. eine Combobox (mit einem Parent), wobei weder die Combobox noch die Parent-Komponente der Combobox auf einer Form liegen. Das geht ohne Probleme, dann greif auf die Items Eigenschaft der Combobox schreibend zu. Genau darin liegt das Problem, das geht nicht (ohne Fehler). Das eigentliche Problem ist und bleibt also, woher weiß man, wann der Parent der Komponente sich ändert. Sagen wir mal die Combobox wird zuerst auf Panel1 gesetzt, Panel1 hat noch keinen Parent, das kann die Combobox ohne Probleme feststellen. Wie merkt sie aber jetzt, das Panel1 auf Panel2 gelegt wurde? Schließlich darf sie erst gefüllt werden, wenn sich über die Parent-Eigenschaft eine Form erreichen lässt (also auch rekursiv mittels if Combo.Parent.Parent is TForm). Und genau das muss man irgendwie wissen, wenn es eine allgemeine Komponente ist, die man z.B. vermarkten möchte. Würde ich eine solche Komponente kaufen, die hier feste Werte in der Combobox stehen hat (was weiß ich, vielleicht Monate), dann möchte ich nicht nach dem platzieren auf einer Form nochmal die Funktion "füllen" aufrufen, damit da auch was drinsteht. Ich würde dann gerne die Möglichkeit haben, die einfach auf einem beliebigen Parent zu platzieren und fertig (z.B. auch dyn.). Und für das Problem sehe ich hier keine Lösung (mag auch sein, dass es für den Threadsteller möglich ist, diese Methode aufzurufen, aber das eigenltiche Problem wäre ebend nicht gelöst). |
Re: Parent Problem
Zitat:
Er erzeugt sein Panel-Combo-Objekt zur Laufzeit. Richtig? Zwei mögliche Fälle: 1.) Er weiß zur Laufzeit, wo das Teil zu liegen kommt. Damit kann er z.B. meinen ersten (Owner=Parent, aber weniger gut) oder meinen letzen Vorschlag (Parent dem Konstruktor mit übergeben) benutzen. Der letzte Vorschlag kam später als Nachtrag und hat sich möglicherweise mit deinem Posting überschnitten. 2.) Der spätere Parent ist selbst vielleicht noch gar nicht erzeugt, wenn das Panel-Combo-Objekt erzeugt wird. Dann übergebe ich "irgendeinen" Parent und setze Visible vom Panel-Combo-Objekt zunächst auf false. Das könnte auch sogar der Konstruktor erledigen, indem er alle Komponenten der Applikation durchsucht und das erstbeste TForm, dass er findet, vorübergehend als Parent nimmt (bei Visible:=false). //EDIT: Posting anders strukturiert, inhaltlich gleichgeblieben. |
Re: Parent Problem
Zitat:
Dann greifst Du auf die Eigenschaft Items zu und eine Exception wird ausgelöst, weil es kein Fenster gibt, dass der Combobox direkt oder über die gesamte Hierachie aller Parents übergeordnet ist. Damit dieses Problem nicht auftritt musst Du also schauen, ob einer der Parents ein Fenster ist, nochmal als Code:
Delphi-Quellcode:
Wichtig ist eben nicht, das ein Parent existiert, sondern das ein Fenster übergeordnet ist.
var b: Boolean;
control: TWinControl; begin b := false; control := Combobox.Parent; while (control <> nil) and (not b) do begin b := control is TForm; control := control.Parent; end; // wenn b an dieser Stelle noch false ist, // dann hast Du ein Problem end; Hoffe es ist jetzt etwas klarer (ist eine Besonderheit der Combobox). [EDIT] Ok, das mit dem visible := false kann natürlich klappen! [/EDIT] |
Re: Parent Problem
Bevor ich möglicherweise noch länger antworten muss ... ;-)
Ich habe vollkommen verstanden, was du meinst. Was stimmt an meinen Lösungsvorschlägen (nimm mein letztes Posting dazu her) denn nicht? |
Re: Parent Problem
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Hier ist doch alles so übergeben, wie Du es vorschlägst oder sehe ich das falsch? Na ja, genau hier dürfte es trotz allem krachen, weil es ebend für die Combobox immer noch kein übergeordnetes Fenster gibt. Wie Du siehst ist hier der spätere Parent schon erzeut, mit der Existenz eines Parents lässt sich das Problem also nicht lösen.
var panel2: TPanel;
x: TMyClass; begin panel2 := TPanel.Create(Form1); x := TMyClass.Create(Form1, Panel2); ... end; Zitat:
|
Re: Parent Problem
Zitat:
Darf ich denn aber nicht voraussetzen, dass das Programm bzw. der Programmierer so etwas abfängt? Ich meine: Viele Komponenten haben Besonderheiten, auf die man während der Programmentwicklung eingehen und achten muss. In einer imaginären Online-Hilfe für diese Komponente stünde eben, dass der Programmierer dafür Sorge zu tragen hat, dass der Parentstammbaum der Komponente "ganz oben" ein Fenster haben muss. Letztendlich soll die Komponente ja irgendwann zur Laufzeit mal sichtbar sein und ein Parent wird zugewiesen werden müssen. Das darf dann eben nicht "irgendetwas" sein, sondern muss einen sauberen WinControl-Stammbaum haben. Dafür muss der Programmierer schon irgendwie sorgen. Warum sollte er auch das Teil auf einer Komponente anzeigen wollen, die selber nicht angezeigt werden kann? :gruebel: Klar könnte man jetzt die Set-Parent-Procedure überschreiben und dort eine Prüfung einbauen. Aber was ist dann? Dann fällt das Programm bei einem "falschen" Parent etwas kontrollierter auf die Schnauze, anstatt nur mit einer Exception. :???: Das hilft auch nicht weiter. Für mich ist Fakt: Zum Zeitpunkt, da Parent irgendwo zur Laufzeit belegt wird, muss dieser Parent sauber sein, oder das Programm fällt auf die Nase. Das kann man auch wohl nicht ändern. Da ist diese Komponente sicherlich keine große Ausnahme, denn mögliche "Fehlbedienungen" gibt es auch bei anderen Komponenten/Klassen. Diese Überlegungen gelten alle auch dann, wenn im Aufruf des Konstruktors diesem der Parent gleich mit übergeben würde. Hier würde ich aber durchaus einsehen, dass der besagte korrekte Parentstammbaum vielleicht noch gar nicht immer existiert. Um also das Createn nicht gleich zu gefährden, könnte dieses hier doch gut funktionieren: Zitat:
Diese sucht sich beim Erzeugen irgendeine Form als funktionierenden "Leihvater" und setzt sich zunächst auf unsichtbar. Im Hauptprogramm muss dann mit Festlegung eines anderen Parent die Box gesondert sichtbar gemacht werden.
Delphi-Quellcode:
constructor TMyCombo.Create(AOwner:TComponent);
begin inherited; Visible:=false; Parent:=SucheParent; Items.Clear; Items.Add('Delphi-Praxis'); Items.Add('Delphi-Forum'); Items.Add('DSDT'); end; function TMyCombo.SucheParent : TWinControl; var i:integer; begin for i:= 0 to Application.ComponentCount-1 do begin if Application.Components[i] is TForm then begin result:=TWinControl(Application.Components[i]); break; end; end; end; |
Re: Parent Problem
Also dein letzter Vorschlag ist bis jetzt die beste Lösung die ich gesehen hab (die scheint auch gut zu funktionieren).
Deshalb nicht falsch verstehen wenn ich sage, dass die ein wenig unsauber wirkt, dachte halt einfach, dass das auch schöner gehen müsste. Aber wie gesagt, die Beste bisher und die sollte auch funktionieren. |
Re: Parent Problem
Zitat:
Zitat:
Aber im Moment könnten wir schon froh sein, wenn der Fragesteller unserer Diskussion überhaupt irgendwie folgen konnte. :angel2: :wink: |
Re: Parent Problem
Das Problem bei einer ComboBox ist, das WINDOWS die Items handhabt. In Konsequenz davon ist die Items-Property erst dann benutzbar, wenn die ComboBox ein Handle hat, und das bekommt sie erst beim ersten 'sichtbarwerden', egal, auf welchem Parent sie liegt(ja man kann theoretisch eine CB auch auf den Desktop setzen). Es hat also nix mit dem Parent-setzen an sich zu tun.
Wenn man also auf die Items zugreifen will, bevor die Box sichtbar ist, muss man also in einem Nachfolger die Items erstmal 'zwischenspeichern', solange die CB noch kein Handle hat (Thema überschreiben der Getter-Setter-Methoden der Items-Property). Sobald die CB dann sichtbar wird (WinHandleAssigned) kann man dann der CB die gemerkten Items unterjubeln. Wenn sie erstml ein Handle hat, dann behält sie es auch, wenn sie unsichtbar wird. nochmal zur Verdeutlichung: es nutzt nix, wenn die CB eine Form als parent hat, solange diese unsichtbar ist. die Items sind erst benutzbar, wenn die CB selber sichtbar wird. |
Re: Parent Problem
Reicht vielleicht auch ein
![]()
Delphi-Quellcode:
constructor TMyCombo.Create(Owner: TComponent);
begin self.Parent := hWnd(-3); //HWND_MESSAGE {...} end; |
Re: Parent Problem
Zitat:
|
Re: Parent Problem
Zitat:
|
Re: Parent Problem
Vielleicht ist es besser, wenn man ein Fenster richtig erstellt:
Delphi-Quellcode:
Sind nur Vorschläge. Wenn ich irgendeine Kommunikation über Windows-Messages kapseln will, mach ich das in der Windowproc so eines TWinControls.
constructor TMyCombo.Create(Owner: TComponent);
begin self.Parent := TWinControl.CreateParented(-3); //beim zuweisen eines "echten" parents nicht das freigeben vergessen! (Setter überschreiben?) {...} end; |
Re: Parent Problem
Zitat:
|
Re: Parent Problem
OK, is in Ordnung. Ich hätte gedacht, dass sich WIndows vielleicht mit dem Mesage-only-window soweit zufrieden gibt, dass alles initialisiert und auch die Items dann schreibbar ist/sind.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:52 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