Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Funktionsaufrufe des Parents vom Child.


muzy - Mi 28.10.09 18:32
Titel: Funktionsaufrufe des Parents vom Child.
Heyho,

die Überschrift ist vlt. etwas verwirrend jedoch hab ich ein kleines Problem.

Ich habe eine Klasse welches ein Objekt instanziert. Dieses Objekt soll nun eine Funktion des Objektes aufrufen welches das Objekt instanziert hat.

Beispiel: Spielfeld instanziet Objekte der Klasse Spielkarte. Diese Spielkarte soll nun eine Funktion "foo" des Spielfeldes aufrufen. Hat da jemand ne Idee wie das gehen kann?


LG

Muzy


Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Mi 28.10.2009 um 17:53


Boldar - Mi 28.10.09 18:34

ich könnte mir höchstens messages vorstellen, oder das Childobjekt muss bei der erstellung ein pointer auf den parent mitkriegen.


muzy - Mi 28.10.09 18:37

Irgendwie muss das gehen, unsere Lehrerin hat uns das so vorgegeben.

Wir übergeben beim Instanzieren Allerdings einen "Aowner" vom Typ Tcomponent, und setzen diesen AOwner vom Typ TComponent auch als Parent.

Vielleicht hilft das als Info weiter.


Critter - Mi 28.10.09 18:42

Hi,

naja warum greifst du dann nicht über Parent daraf zu:


Delphi-Quelltext
1:
2:
if (parent is tSpielfeld) then
  tSpielfeld(parent).foo;


Immer vorrausgesetzt, das tSpielfeld auch als Parent von tSpielKarte ist.

critter


thepaine91 - Mi 28.10.09 18:42

Was für ein Objekt denn? Objekt ist ziemlich dehnbar.


muzy - Mi 28.10.09 18:45

Dieses tSpielfeld(parent).foo geht nicht, da bekomme ich einen udnefinierten Bezeichner.

Erwähnenswert ist das ich mit Delphi 6 arbeiten muss.

self.parent.foo geht ebenfalls nicht -- auch ein Undefinierter Bezeichner.


Xentar - Mi 28.10.09 18:47

nud was genau ist undefiniert?


elundril - Mi 28.10.09 18:48

wie wärs mit


Delphi-Quelltext
1:
2:
if (Parent is TSpielfeld) then
  (Parent as TSpielfeld).foo();


lg elundril


muzy - Mi 28.10.09 18:50

Der Bezeichner "foo" ist undefiniert.

Hier mal die Sourcen:

Spielfeld:

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:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
unit mSpielfeld;

interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, mKarte;
type

 
 TSpielfeld = class
  protected

  private
   hPunktestand,zeilen,spalten,curzeile,curspalte,curleft,curtop,anzkarten: integer;
   kartenmischer: array[1..24of integer;  //maximal 48 Karten
   kartenarray: array[1..48of TKarte;

  public

   constructor Create(AOwner: TComponent;pAnzkarten:Integer); virtual;
   destructor destroy;
   procedure setPunktestand(pPunktestand: integer);
   function getPunktestand: integer;
   procedure ZeigeFeld (AOwner: TComponent);
   function Mischen: integer;
   procedure ZeilenSpaltenHelfer;
   procedure SetzeZeilenSpalten;
   procedure foo;

end;


implementation

constructor TSpielfeld.Create(AOwner: TComponent;pAnzKarten:Integer);
var i:integer;
begin
 inherited create;
 
 curtop := 50// Wird benutzt zum lustigen Kartensetzen ;)
 curleft := 8// s.o.
 curzeile := 1;
 curspalte := 1;

 anzkarten := pAnzKarten; // Muss durch 2 Teilbar sein empfohlene Werte: [8,16]
 ZeilenSpaltenHelfer;   // Zur weiteren Initialisierung

 for i:= 1 to anzkarten do
 begin
  kartenarray[i] := TKarte.create(AOwner, Mischen);
   kartenarray[i].Name   := 'Karte' + InttoStr(i);
   kartenarray[i].Height := 100;
   kartenarray[i].Width  := 100;
   kartenarray[i].left  := curleft;
   kartenarray[i].top  := curtop;
   kartenarray[i].Parent := (AOwner as TWinControl);
   SetzeZeilenSpalten;

 end;

end;

procedure TSpielFeld.foo;
begin

showmessage('foo');

end;

procedure TSpielFeld.SetzeZeilenSpalten;
begin
 if curspalte = spalten then
  begin
    curspalte := 1;
    curzeile := curzeile +1;
  end
  else
  begin
    curspalte := curspalte +1;
  end;  
 case curzeile of
   1: curtop := 50;
   2: curtop := 152;
   3: curtop := 254;
   4: curtop := 356;
   5: curtop := 458;
   6: curtop := 560;
 end;
 case curspalte of
   1: curleft := 8;
   2: curleft := 110;
   3: curleft := 212;
   4: curleft := 314;
   5: curleft := 416;
   6: curleft := 518;
   7: curleft := 620;
 end;
end;

procedure TSpielFeld.ZeilenSpaltenHelfer;
begin
  case anzkarten of
         4:begin zeilen:=2;spalten:=2end;
         6:begin zeilen:=2;spalten:=3end;
         8:begin zeilen:=2;spalten:=4end;
        10:begin zeilen:=3;spalten:=4end;
        12:begin zeilen:=3;spalten:=4end;
        16:begin zeilen:=4;spalten:=4end;
      //  20:begin zeilen:=5;spalten:=4; end;
      //  24:begin zeilen:=6;spalten:=4; end;
  end;
end;

function TSpielFeld.Mischen:integer;
var tmp,success,res,randzahl:integer;
begin
  success := 0;
  randzahl := round(anzkarten / 2);
  while success = 0 do
  begin
    tmp := random(randzahl)+1;
    if (kartenmischer[tmp] < 2and (tmp <> 0and (tmp <= randzahl) then  // error handling
    begin
      success := 1;
      res := tmp;
      kartenmischer[tmp] := kartenmischer[tmp] +1;
    end;
  end;
  result := res;
end;

procedure TSpielFeld.ZeigeFeld (AOwner: TComponent);
var i:integer;
begin
 for i:=1 to anzkarten do
 begin
    kartenarray[i].Visible:=true;
 end;
end;


destructor TSpielfeld.destroy;
var i:integer;
begin
 inherited destroy;
 for i:=1 to anzkarten do
 begin
    kartenarray[i].destroy;
 end;
end;

procedure TSpielfeld.setPunktestand(pPunktestand: integer);
begin
end;

function TSpielfeld.getPunktestand: integer;
begin
end;
end.


Karte:

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:
unit mKarte;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type


  TKarte = class(TImage)
   procedure BeiClick (Sender: TObject); // Selbstdefinierte onClick-Methode

  private
   hWert:  integer;
   zVerdeckt: Boolean;

  public
   constructor create(AOwner: TComponent; pWert: integer); virtual;
   destructor destroy;
   procedure setWert (pWert: integer);
   function getWert: integer;
   procedure setVerdeckt (pVerdeckt: Boolean);
   function getVerdeckt: Boolean;
  end;

implementation

constructor TKarte.create (AOwner: TComponent; pWert: integer);
begin
 inherited Create (AOwner);
 self.Picture.LoadFromFile('rueck.bmp');
 self.OnClick := BeiClick;
 self.Visible := False;
 zVerdeckt := True;
 hWert := pWert;
end;


procedure TKarte.BeiClick (Sender: TObject);
begin
if zVerdeckt then
 begin
  self.Picture.LoadFromFile(IntToStr(self.hWert) + '.bmp');
  zVerdeckt := not zVerdeckt;
 end;

 // HIER FOO METHODE VOM PARENT (SPIELFELD)

end;

destructor TKarte.destroy;
begin
 inherited destroy;
 
end;

procedure TKarte.setWert(pWert: integer);
begin
  hWert:=pWert;
end;

function TKarte.getWert: integer;
begin
 result := hWert;
end;


procedure TKarte.setVerdeckt (pVerdeckt: Boolean);
begin
 zVerdeckt := pVerdeckt;
end;

function TKarte.getVerdeckt: Boolean;
begin
 result := zVerdeckt;
end;

end.

Ich verstehe einfach nicht warum das nicht so simpel geht :/

Btw, alle eure Ideen geben den undefinierten Bezeichner aus. Der meint immer "foo" ist undefiniert.

Moderiert von user profile iconNarses: Code aus den Links eingefügt.


elundril - Mi 28.10.09 18:52

foo() ist eine beispielprocedure. da wir nicht wissen was für eine procedure ausführen willst, schreiben wir einfach foo() hin. also, ersetze foo() durch den namen deiner Procedure und fertig. gegebenenfalls noch die parameter anpassen. ;)

lg elundril


muzy - Mi 28.10.09 18:53

Oehm, es gibt die Funktion TSpielfeld.foo ;)


elundril - Mi 28.10.09 18:54

aso, wusst ich nicht...

hast du den namen der unit in der TSpielfeld ist ins uses von der Unit in der TKarte drin ist reingeschrieben?

lg elundril


HelgeLange - Mi 28.10.09 18:55

Du musst schaun, dass Spielfeld bekannt ist, wenn Du den Parent drauf castest. Also unit einbinden zum Bsp.
Auch solltest Du nicht den parent nehmen, sondern den Owner. Parent ist für Zeichnen von WinControls verantwortlich, Owner ist der Besitzer des Objects. Also wenn dein Spielfeld die Karte erstellt mit

MeineKarte := TSpielKarte.Create(Self);  // self ist das Spielfeld

dann ist der owner ganz sicher dein Spielfeld.


muzy - Mi 28.10.09 18:56

das geht nicht da sich das sonst überkreuzt. TSpielfeld hat sinnvollerweise die Karte (TKarte) drinnen, in TKarte kann ich allerdings nicht das Spielfeld in die uses schreiben, alles schon probiert.

---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

und self.Owner.foo funktioniert ebenfalls auch nicht :(


Xentar - Mi 28.10.09 18:58

user profile iconmuzy hat folgendes geschrieben Zum zitierten Posting springen:
das geht nicht da sich das sonst überkreuzt. TSpielfeld hat sinnvollerweise die Karte (TKarte) drinnen, in TKarte kann ich allerdings nicht das Spielfeld in die uses schreiben, alles schon probiert.

Klar, in die Uses unter Implementation.

Aber warum machst du für sowas nicht ein neues Ereignis?


Critter - Mi 28.10.09 18:59

user profile iconmuzy hat folgendes geschrieben Zum zitierten Posting springen:
und self.Owner.foo funktioniert ebenfalls auch nicht :(

Hi, da musst du auch wieder auf tSpielfeld Casten

also tSpielFeld(Owner).foo;.

critter


muzy - Mi 28.10.09 19:00

Wenn cih ehrlich bin hab ich keine Ahnung,

wie in den Sourcen hab ich halt, bzw hat jede Karte ein BeiClick Ereignis, dieses soll dem Spielfeld mitteilen das es geklickt wurde. Sprich es muss eine Funktion des Spielfeldes aufrufen.


muzy - Mi 28.10.09 19:02

Ah nachdem ich im Implementation Teil (und nciht im Interface Teil) ein eigenes "uses" einbaute hat es geklappt. Kann mir wer erklären was dieses Uses im Implementation Teil von dem im Interface Teil unterscheidet?


martin300 - Mi 28.10.09 19:05

user profile iconmuzy hat folgendes geschrieben Zum zitierten Posting springen:
Heyho,

Beispiel: Spielfeld instanziet Objekte der Klasse Spielkarte. Diese Spielkarte soll nun eine Funktion "foo" des Spielfeldes aufrufen. Hat da jemand ne Idee wie das gehen kann?
Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Mi 28.10.2009 um 17:53

Im Prinzip kann alles vom Spielfeld aus zugegriffen werden. Dort ist auch ein Array mit den 48 Karten gespeichert.


elundril - Mi 28.10.09 19:06

darf ich dir Christian's Crashkurs [http://www.christian-stelzmann.de/index_tutorials_crashkurs.html] empfehlen Muzy? Ich denke, es wäre hilfreich für dich!

lg elundril


muzy - Mi 28.10.09 19:10

Danke Elundril, (und all den anderen natürlich auch)

nur das mit den Uses im Implementation Teil ist mir noch gänzlich neu -- hat man uns wohl versäumt beizubringen. Aber ich werd das nochmal genau nachlesen. Auf jeden Fall schonmal vielen Dank für eure Hilfe


HelgeLange - Do 29.10.09 02:07

Aber warum nimmst Du dann nicht events ?
Du definierst ein OnClick event (wenn nicht schon da) bei der Karte und hängst das Ereignis im Spielfeld an diesen event handler.


thepaine91 - Do 29.10.09 09:27

Das wäre noch besser ;)