Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Control " has no parent window bei TCombobox
catweasel - Mo 17.11.03 21:04
Titel: Control " has no parent window bei TCombobox
Hi,
Zunächst vorneweg:
Eine ähnliche Frage hat es hier schonmal im VCL Forum gegeben. Ich finde aber hier ist sie auch gut aufgehoben. (Bitte lieber Moderator, hau mich nich :wink: )
Bei dem anderen Post mit dieser Frage trat das Problem zur Designzeit auf. Bei mir tritt es zur Laufzeit auf :-(
Ich habe folgendes Problem:
Ich erstelle eine Combobox auf einem Panel, nicht zur Designzeit, sondern zur Laufzeit:
Das sieht in etwa so aus :
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90:
| unit Superchart;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type TSuperchart = class(twincontrol) private heimtore : integer; gasttore : integer; anzeige : TPanel; heimdisplay : TCombobox; gastdisplay : TCombobox; heimtordisplay : TEdit; gasttordisplay : TEdit; abpfiff : TButton; spiellabel : TLabel; heimlabel : TLabel; gastlabel : TLabel; heimtorlabel : TLabel; gasttorlabel : TLabel; procedure setlabel(labeltext :string); function getlabel : string; procedure abpfiffklick(Sender : TObject); procedure heimtordisplayklick(Sender : TObject); procedure gasttordisplayklick(Sender : TObject);
protected
public constructor Create(Owner: TComponent; xalign, yalign : integer); destructor Destroy; override; procedure setfarbe(farbe :TColor); function wersieger : string; function torvorsprung : integer;
published property spielname: string read getlabel write Setlabel; end;
... (einiges irrelevantes weggekürzt)
constructor TSuperchart.Create(Owner: TComponent; xalign, yalign : integer); var topalign_head : integer; topalign_display : integer; begin inherited create(Owner); topalign_head := 20; topalign_display := 5; heimtore := 0; gasttore := 0;
left := xalign; top := yalign; height := 75; width := 630;
anzeige := TPanel.Create(Self); with anzeige do begin Parent := self; height := self.height -15; width := self.Width; Top := 15; end;
heimdisplay := TCombobox.Create(self); with heimdisplay do begin Parent := anzeige; Width := 180; left := 5; Top := topalign_head; end;
gastdisplay := TCombobox.Create(self); with gastdisplay do begin Parent := anzeige; Width := 180; left := 225; Top := topalign_head; end;
heimdisplay.Text := 'Testmannschaft'; end; |
Es soll also beim erzeugen des Objekts der Inhalt der Textdatei in die Comboboxen geladen werden...
aber jeder Aufruf einer Methode der Combobox wie z.b.
oder
Delphi-Quelltext
1:
| heimdisplay.items.add('Mannschaftsname'); |
führt zu der Fehlermeldung:
Zitat: |
Control " has no parent window. |
Obwohl doch
Anzeige als Parent festgelegt wurde. :(
Aus den Postsa zu dem Thema bin ich nicht schlau geworden.
Holf mir mal bitte einer.....
Catweasel
Moderiert von
Tino: Delphi- & Quote-Tags hinzugefügt.
barfuesser - Di 18.11.03 17:47
Kann es sein, daß Dein SuperChart kein ParentWindow hat?
barfuesser
Mossi - Di 18.11.03 20:44
Ich hab jetzt zwar gerade kein Delphi zur Hand aber versuch mal folgendes:
Quelltext
1:
| heimdisplay := TCombobox.Create(anzeige); |
Bin mir zwar jetzt nicht hundertprozentig sicher, ob es so klappt, aber wenn ich mich recht erinnere, hab ich es auch so gemacht (siehe oben genanntes Problem)
EDIT: Zusätzlich aber auch noch die Parenteigenschaft setzen
Tendl - Fr 23.01.04 15:03
Ich kämpfe momentan mit dem gleichen Problem, habe aber sicher einen Parent definiert:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| ComboBox1 := TComboBox.create(self); ComboBox1.top := 10; ComboBox1.left := 80; ComboBox1.parent := self; combobox1.Items.Add('Diashow'); combobox1.Items.Add('Unerase'); combobox1.Items.Add('Move'); combobox1.Items.Add('Copy'); combobox1.Items.Add('Save'); combobox1.Items.Add('Undo'); |
Die Fehlermeldung kommt nach den ersten Items.Add. Wenn ich auf die Items.Adds verzichte funktioniert es soweit (mit fehlender Textliste).
Wie war den Eure Lösung?
Thomas
Motzi - Fr 23.01.04 16:14
Das Problem ist wahrscheinlich, dass dein SuperChart zu dem Zeitpunkt zu dem du die Controls erzeugst selbst noch keinen Parent hat...
@Tendl: wo steht dieser Code? Also wann erzeugst du die Combobox? Was ist Self für ein Objekt?
Tendl - Fr 23.01.04 17:04
Hallo Motzi,
der Code steht in einer abgeleiteten Klasse von TCustomPanel
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
| TButton_Setup = class(TCustomPanel) private Label1: TLabel; ComboBox1: TComboBox; protected published public constructor create(AOwner: TComponent); override; end;
.....
constructor TButton_Setup.create(AOwner: TComponent); begin inherited create(AOwner); align := alClient;
Label1 := TLabel.create(self); with label1 do begin top := 10; left := 20; height:=20; caption := 'Action:'; parent := self; end;
ComboBox1 := TComboBox.create(self); ComboBox1.top := 10; ComboBox1.left := 80; ComboBox1.parent := self; combobox1.Items.Add('Diashow'); combobox1.Items.Add('Unerase'); combobox1.Items.Add('Move'); combobox1.Items.Add('Copy'); combobox1.Items.Add('Save'); combobox1.Items.Add('Undo'); end; |
Das Instanz von TButton_Setup liegt seinereits auf eine Tabsheet auf einem Panel auf einem Formular;
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55:
| TPanelbar_Setup = class(TCustomForm) private protected public Panel2: TPanel; PageControl1: TPageControl; TabSheets: array[1..10] of TTabSheet; TButton_Setups: array[1..10] of TButton_Setup; constructor create(AOwner: TComponent); override; published end;
.....
constructor TPanelbar_Setup.create(AOwner: TComponent); var i: integer; begin inherited createnew(AOwner); caption := 'Setup Workarea'; self.Height := 300; self.Width := 600; self.Top := 200; self.Left := 200;
Panel2 := TPanel.Create(Self); Panel2.Name := 'Panel2'; Panel2.Parent := self; Panel2.Align := alBottom; Panel2.Height := 200; panel2.Caption := 'Panel2'; PageControl1 := TPageControl.Create(Panel2); PageControl1.Parent := panel2; PageControl1.Name := 'PageControl1'; PageControl1.Align := alClient;
for i := 1 to 10 do begin TabSheets[i] := TTabSheet.Create(PageControl1); TabSheets[i].Parent := PageControl1; TabSheets[i].PageControl := PageControl1; TabSheets[i].Caption := 'Button ' + inttostr(i); TabSheets[i].Name := 'TabSheet' + inttostr(i); TButton_Setups[i] := TButton_setup.create(self); TButton_Setups[i].Parent := TabSheets[i]; end;
end; |
Die Instanz von TPanelbar_Setup wird ebenfalls zur Laufzeit erzeugt mit
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TSpecThumbWorkArea.BtnClick1(Sender: TObject); var setup: TPanelbar_Setup; begin setup := TPanelbar_Setup.create(setup); setup.ShowModal; setup.Free; end; |
Wie beschrieben klappt alles, wenn ich die Items.Add() weglasse.
Der Fehler kommt erst, wenn ich versuche die Items beim Create vorzubelegen.
Sorry, für den vielen Code, aber so werden die Zusammenhänge klarer.
Wenn Du Zeit und Lust hast, dann schau bitte mal rein.
Danke Thomas
Tendl - Mo 26.01.04 13:53
Das Problem ist gelöst:
In der Routine befinden sich die Zeilen
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| constructor TPanelbar_Setup.create(AOwner: TComponent); var i: integer; begin inherited createnew(AOwner);
for i := 1 to 10 do begin TButton_Setups[i] := TButton_setup.create(self); TButton_Setups[i].Parent := TabSheets[i]; end |
;
Die vorletzte Zeile weist den Parent zu, d.h. im TButton_setup.create wird dies nicht getan. Damit ergeben sich die genannten Probleme, nicht nur bei Comboboxen sondern z.B auch bei Radiogroups.
Die Korrektur lautet:
Delphi-Quelltext
1:
| TButton_Setups[i] := TButton_setup.create(TabSheets[i]); |
Und im Create von TButton_setup:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| constructor TButton_Setup.create(AOwner: TComponent); var itemlist:TStringlist; begin inherited create(AOwner); parent:=TWINControl(AOwner); /.... end; |
Mir ist das Problem damit klar, ich hoffe anderen auch
Thomas
catweasel - Mo 26.01.04 14:34
ja, dieses Problem lässt sich so tatsächlich lösen. Aber da gibts noch ein paar andere Klippen...
hab das mit dem Control " has no parent window mal ein bischen unter die Lupe genommen....
Es sieht für mich folgendermassen aus:
Klingt vielleicht ein bischen Konfus, aber so stellt sich das durch rumprobieren für mich dar...:
These: Ein Objekt existiert erst wirklich dann wenn der Constructor wirklich und endgültig abgeschlossen ist....
weil : keine Methode die NUR als Methode implementiert ist funktioniert..... Man kann keine Listboxen füllen, nicht auf den Canvas einer Paintbox malen, etc....
Nur was als Property deklariert ist (width, top, etc.....) lässt sich im Constructor verwenden. (Als Ausnahme konnte ich nur die LoadFromFile() funktion von TImage finden).
@Tendel
auch wenn man die Parent Zuweisung NICHT vergessen hat, kann einem diese Meldung begegnen.....
Das wäre auch möglich...
Verlagere deinen Code mit den items.Add() einfach in eine eigene Funktion die du im Hauptprogramm direkt nach dem create() ausführen lässt....
combo1 := TComboBox.create(self);
combo1.fuellen;
dann funktioniert es.....
Das Unschöne dabei ist: Dadurch das man "extra nur deswegen" eine Prozedur oder Funktion öffentlich machen muss :-(
Nach meiner Auffassung von OOP wäre es am elegantesten wenn nichts ausser "Übergaberoutinen" öffentlich sind.....
Catweasel
Motzi - Mo 26.01.04 16:21
@catweasel: Methoden die erst nach Abarbeitung des Constructors ausgeführt werden sollen kann man auch anders lösen...
TObject führt nämlich eine virtuelle Methode namens "AfterConstruction" ein, die immer automatisch sofort nach dem Constructor aufgerufen wird (zB löst die TForm das OnCreate-Event in ihrer überschriebenen Version dieser Methode aus).
Aber die Meldung "Control xxx has no parent window" kann einem auch durchaus außerhalb des Constructors begegnen...!
catweasel - Mo 26.01.04 19:12
Zitat: |
Aber die Meldung "Control xxx has no parent window" kann einem auch durchaus außerhalb des Constructors begegnen...! |
Ja, das kann sie.. Da aber, im Falle des Auftauchens während der Abarbeitung eines Constructors deuten die " zwei Einfachen Anführungszeichen auf einen leeren Komponentennamen hin......
Eigentlich sollte der aber bereis existieren, oder?
es ist ja eben nicht
...control 'xxx' has no... , sondern
control " has no...
Catweasel
Motzi - Mo 26.01.04 21:22
Ja, richtig... das '' deutet auf einen leeren Komponentennamen hin, aber wo sollte zum Zeitpunkt der Ausführung des Constructors denn bereits ein Name existieren? Bei zur Laufzeit erstellten Komponenten bist schließlich du dafür verantwortlich ihnen einen Namen zu verpassen (sofern es überhaupt notwendig ist - man kann den Namen auch einfach leer lassen).
Du darfst an dieser Stelle halt nicht Klassenname (zb TButton) und Komponentenname (zb Button1) verwechseln...!
XelaRellum - Mi 15.03.06 13:02
Titel: Überschreiben von "SetParent" hat bei mir gut funktioniert.
Ich hatte eben ein ganz ähnliches Problem: ich hatte ein eigenes Control erzeugt, dass auf einem Tabsheet wiederum eine TComboBox anlegt und der dann auch gleich ein paare Werte zuweist. Bei mir liess sich das Problem (ohne Änderungen an anderen Programmteilen) entfernen, indem ich "SetParent" überschrieben habe und dort dann die ComboBox Werte hinzugefügt habe. Dies nur zur Info
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!