Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - Und noch ein mal: Element hat kein übergeordnetes Fenster


Peter18 - Di 14.08.12 10:33
Titel: Und noch ein mal: Element hat kein übergeordnetes Fenster
Ein freundliches Hallo an alle,

leider habe ich im Forum keine Lösung gefunden, daher folgendes Problem:

Ich verwende Delphi 4 und erzeuge neue Komponenten. Bisher lief es gut.

Die Basis meiner Komponente ist TPanel. Darauf werden verschiedene andere Komponenten wie Label Combobox, Panel u.s.w arangiert. Als ich nun TRadioGroup erzeugen wollte erhielt ich bei


Delphi-Quelltext
1:
"oNewTerm.Items.Add( 'Dauer' );"                    

die Fehlermeldung. Parent wird jedoch zugewiesen.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
constructor T_TagesListe.Create( Owner: TComponent );
var
  R, C       : Integer;

begin
  inherited Create( Owner );
  inherited Parent := TWinControl( Owner );
.
.
.
  oNewTerm        := TRadioGroup.Create( Self );      
  oNewTerm.Parent := Self;
  oNewTerm.Items.Add( 'Dauer'   );  // Fehler!!!

Es scheint ein besonderer Type Parent notwendig zu sein. Doch welcher und warum? Wenn ich TWinControl( Owner ); zuweise erhalte ich die gleiche Meldung.

Ich hoffe jemand hat einen heißen Tip auf Lager.

Grüße von der sonnigen Nordsee

Peter


Delete - Di 14.08.12 15:38

ExtCtrls in der uses List? (für TRadioGroup)
//Edit: blöd, dann würde es ja sowieso nicht gehen...


jaenicke - Di 14.08.12 16:41

Zu dem Zeitpunkt ist das Fensterhandle schlicht noch nicht erzeugt, deshalb geht das so nicht. :nixweiss:
Wie wäre es mit einem Frame statt dem Panel? Dann kannst du das visuell designen und dann aufs Formular legen wie eine Komponente.


Martok - Mi 15.08.12 20:51

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Zu dem Zeitpunkt ist das Fensterhandle schlicht noch nicht erzeugt, deshalb geht das so nicht. :nixweiss:
Dann würde aber das vorher auch nicht gehen. AFAIR wird wenn man Parent zuweist das solange zurückgehalten bis mal jemand HandleNeeded aufruft.
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Wie wäre es mit einem Frame statt dem Panel? Dann kannst du das visuell designen und dann aufs Formular legen wie eine Komponente.
Delphi 4, vor 14 Jahren gabs sowas noch nicht.

2 Sachen: welcher Fehler tritt denn auf? Fehler!!! ist eine Null-Aussage. /€: oh, steht ja im Thementitel. Da hab ich nicht gesucht :D

Außerdem: teste das mal so, in D7 funktioniert das.

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:
  TFoo = class(TPanel)
  private
    FRG: TRadioGroup;
  public
    constructor Create(AOwner: TComponent); override;
  end;

{ TFoo }

constructor TFoo.Create(AOwner: TComponent);
begin
  inherited;
  Parent:= TWinControl(AOwner);
  Width:= 300;
  Height:= 300;

  FRG:= TRadioGroup.Create(Self);
  FRG.Parent:= Self;
  FRG.Align:= alClient;
  FRG.Caption:= 'testgroup';
  FRG.Items.Add('Check 1');
  FRG.Items.Add('Check 2');
  FRG.Items.Add('Check 3');
end;

//...

procedure TForm1.Button1Click(Sender: TObject);
begin
  TFoo.Create(Self); // jaja speicherleck und so, ich weiß
end;


jaenicke - Mi 15.08.12 21:42

user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Wie wäre es mit einem Frame statt dem Panel? Dann kannst du das visuell designen und dann aufs Formular legen wie eine Komponente.
Delphi 4, vor 14 Jahren gabs sowas noch nicht.
Ok, das wusste ich nicht, da ich Delphi 4 nie hatte. Wenn es die dort noch nicht gab, wurden die mit Delphi 5 eingeführt.

user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
Außerdem: teste das mal so, in D7 funktioniert das.
Mit Delphi 5 auch. :zustimm:


Peter18 - So 26.08.12 11:24

Ein freundliches Hallo von der verregneten Nordsee,

Dank euch für die Antworten, und entschuldigt meine späte Reaktion, war außer Haus.

Zwischendurch hatte ich einen workaround mit den Radiobutton erstellt. Da die Radiogroup sowieso zunächst unsichtbar sein soll, kann ich in diesem Fall beim sichtbar Schalten der Radiogroup die Länge der Item-Liste prüfen und sie dann hinzufügen. Damit wäre das Problem gelöst.

Ich habe aber ein weiteres Problem, das eventuell die gleiche Ursache hat:
Die Basis ist auch hier ein Panel. Im constructor wird eine Routine aufgerufen, die einen Rahmen um ein Label zeichnet, um es hervorzuheben. Wärend der Laufzeit wird die Markierung gelöscht und ein anderes Element markiert. Wenn das Formular aufgebaut wurde fehlt die Markierung, wechselt die Markierung jedoch auf ein anderes Element, so ist sie sichtbar. Die Markierung wird durch properties gesteuert, die im constructor des Panels gesetzt werden. Sie später durch einen Button zu aktivieren ist nicht sinnvoll, das muß automatisch gehen!


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:
// ############################################## Objekt-Hilfsroutinen

procedure T_Monat_Kalender.PaintRect;
var
  R, C : Integer;

begin
  if oTag > 0 then
  begin
    GetTagIndex( R, C, oTag );
    Self.Canvas.Pen.Width := 2;
    Self.Canvas.Pen.Color := clBlack;
    Self.Canvas.MoveTo( C * CellWidth + 9,             R * CellHeight + PTo - 1 );
    Self.Canvas.LineTo( C * CellWidth + CellWidth + 9, R * CellHeight + PTo-1);
    Self.Canvas.LineTo( C * CellWidth + CellWidth + 9, R * CellHeight + CellHeight + PTo-1);
    Self.Canvas.LineTo( C * CellWidth + 9,             R * CellHeight + CellHeight + PTo-1);
    Self.Canvas.LineTo( C * CellWidth + 9,             R * CellHeight + PTo - 1 );
    oRectR := R;
    oRectC := C;                                                               
  end;
end;

// ############################################## Objekt-Hilfsroutinen


Der Versuch das Problem durch ein Objekt zu beheben, führte dazu, dass beim Beenden der Anwendung die Fehlermeldung "Element hat kein übergeordnetes Fenster" erscheint. Kommentiere ich dieses Objekt heraus, so erscheint die Meldung nicht. Das Objekt erscheint auch nicht auf dem Panel.

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:
T_Rect = class(TGraphicControl)

  private
    oTop    : Integer;
    oLeft   : Integer;
    oHeight : Integer;
    oWidth  : Integer;
    oColor  : TColor;
    oBackgr : TColor;
    oLine   : Integer;
    oParent : TWinControl;

    procedure WriteTop    ( I : Integer     );
    procedure WriteLeft   ( I : Integer     );
    procedure WriteHeight ( I : Integer     );
    procedure WriteWidth  ( I : Integer     );
    procedure WriteColor  ( C : TColor      );
    procedure WriteBackgr ( C : TColor      );
    procedure WriteLine   ( I : Integer     );
    procedure WriteParent ( P : TWinControl );

  public
    constructor Create( Owner: TComponent );                           override;
    destructor  Destroy;                                               override;
    procedure   Paint;                                                 override;

  published
    property Top           : Integer        Read oTop             Write WriteTop;
    property Left          : Integer        Read oLeft            Write WriteLeft;
    property Height        : Integer        Read oHeight          Write WriteHeight;
    property Width         : Integer        Read oWidth           Write WriteWidth;
    property Color         : TColor         Read oColor           Write WriteColor;
    property Backgr        : TColor         Read oBackgr          Write WriteBackgr;
    property Line          : Integer        Read oLine            Write WriteLine;
    property Parent        : TWinControl    Read oParent          Write WriteParent;

    procedure Clr;

end;

// #############################################################################
//   Constructor, Destructor
// #############################################################################

constructor T_Rect.Create( Owner: TComponent );
begin
  inherited Create( Owner );
  Owner.InsertComponent( Self );
  oTop    := 0;
  oLeft   := 0;
  oHeight := 10;
  oWidth  := 10;
  oColor  := clBlack;
  oBackgr := clBtnFace;
  oLine   := 1;
end;

// ########################################### Constructor, Destructor

Zur Laufzeit wird keine Fehlermeldung ausgegeben, auch beim Wechsel der Markierungen nicht, nur beim Beenden der Anwendung.

Wäre schön, wenn jemand eine Erklärung hätte, eine Lösung wär phantastisch!

Freundliche Grüße an alle

Peter


mandras - So 26.08.12 15:36

Versuch doch mal beim Create das Formular anzugeben, nicht die übergeordnete Komponente.

Ich habe Dein Programm nicht getestet, normalerweise sollte der Owner immer die jeweilige Form sein und Parent die übergeordnete Komponente.


jaenicke - So 26.08.12 16:06

Ich frage mich gerade, warum du versuchst die Komponente doppelt dem Owner hinzuzufügen (einmal im geerbten Konstruktor und einmal mit InsertComponent)? :shock:
Ich nehme zwar an, dass InsertComponent prüft, ob die Komponente schon drin ist, aber wenn nicht, knallt das beim Freigeben logischerweise...

Ein Beispielprogramm wäre hier sehr hilfreich, denn so lässt sich das nicht so einfach nachvollziehen.


Peter18 - So 26.08.12 17:51

Hallo mandras, hallo jaenicke,

Danke für Eure Antworten.

Mit dem Formular klappt das leiter nicht. Das Panel, das T_Rect erzeugt ist wiederum ein Objekt eines Panels, das mehrere andere trägt. Dieses Panel Basis-Panel wird vom Formular erzeugt.

InsertComponent war nur ein Versuch, da das Rechteck nicht sichtbar wurde und beim Schließen der Anwendung die bekannte Fehlermeldung erschien.

Hier ist das Objekt:

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:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
// #############################################################################
//   Ereignisroutinen
// #############################################################################



// ################################################## Ereignisroutinen



// #############################################################################
//   Objekt-Hilfsroutinen
// #############################################################################

procedure T_Rect.Draw;
begin
  Self.Canvas.MoveTo( oTop,           oLeft          );
  Self.Canvas.LineTo( oTop,           oLeft + oWidth );
  Self.Canvas.LineTo( oTop + oHeight, oLeft + oWidth );
  Self.Canvas.LineTo( oTop + oHeight, oLeft          );
  Self.Canvas.LineTo( oTop,           oLeft          );
end;

// ##################################################### Hilfsroutinen



// #############################################################################
//   Properties
// #############################################################################

procedure T_Rect.WriteTop( I : Integer );
begin
  oTop := I;
end;

// ######################################################## Properties

procedure T_Rect.WriteLeft( I : Integer );
begin
  oLeft := I;
end;

// ######################################################## Properties

procedure T_Rect.WriteHeight( I : Integer );
begin
  oHeight := I;
end;

// ######################################################## Properties

procedure T_Rect.WriteWidth( I : Integer );
begin
  oWidth := I;
end;

// ######################################################## Properties

procedure T_Rect.WriteColor( C : TColor );
begin
  oColor := C;
end;

// ######################################################## Properties

procedure T_Rect.WriteBackgr( C : TColor );
begin
  oBackgr := C;
end;

// ######################################################## Properties

procedure T_Rect.WriteLine( I : Integer );
begin
  oLine := I;
end;

// ######################################################## Properties

procedure T_Rect.WriteParent( P : TWinControl );
begin
  oParent          := P;
  inherited Parent := P;
end;


// #############################################################################
//   Methoden
// #############################################################################

procedure T_Rect.Paint;                                             
begin
  Self.Canvas.Pen.Width := oLine;
  Self.Canvas.Pen.Color := oColor;
  Draw;
end;

// ########################################################## Methoden

procedure T_Rect.Clr;
begin
  Self.Canvas.Pen.Width := oLine;
  Self.Canvas.Pen.Color := oBackgr;
  Draw;
end;

// #############################################################################
//   Constructor, Destructor
// #############################################################################

constructor T_Rect.Create( Owner: TComponent );
begin
  inherited Create( Owner );
//  Owner.InsertComponent( Self );
  oTop    := 0;
  oLeft   := 0;
  oHeight := 10;
  oWidth  := 10;
  oColor  := clBlack;
  oBackgr := clBtnFace;
  oLine   := 1;
end;

// ########################################### Constructor, Destructor

destructor T_Rect.Destroy;
begin
  Clr;
  inherited Destroy;
end;


Das ist der Code im constructor des übergeordneten Panels:

Delphi-Quelltext
1:
2:
3:
4:
5:
  oMark        := T_Rect.Create( Owner );
  oMark.Parent := Self;
  oMark.Height := CellHeightMin;
  oMark.Width  := CellWidthMin;
  oMark.Line   := 2;

Und das ist der Teil, wenn das Rechteck gezeichnet werden soll:

Delphi-Quelltext
1:
2:
3:
    oMark.Top  := R * CellWidth + 9;
    oMark.Left := C * CellHeight + PTo - 1;
    oMark.Paint;


Grüße von der Nordsee

Peter


Peter18 - Do 06.09.12 18:00

Ein freudliches Hallo an alle,

schade, dass mir niemand sagen kann, warum die Fehlermeldung kommt. Irgend etwas muß da doch noch fehlen.

Habe das Problem erst ein mal kaschiert, und im Formular OnPaint die Property neu gesetzt. Damit erscheint der Rahmen. Unschön aber geht.

Grüße von der Nordsee

Peter


mandras - Do 06.09.12 19:13

Setz doch bitte einmal einen Quelltext hier ein den man ohne überarbeiten übersetzen kann