#1 01.10.2005 13:44:31

artzuk
GodlikeMember
Ort: Leipzig
Registriert: 24.01.2005
Beiträge: 1164

Engine Variable

Die Enginevariable muss ja irgendwo deklariert werden. Wir hatten zwar dazu mal eine mirc-session, aber leider habe ich den Ansatz wieder vergessen.
Ich weis jetzt nicht, wo ich die Enginevariable hinsetzen soll.

Ich hatte mir es so hier gedacht:

Code: delphi

program enginedemo;

//... Compilerzeugs

uses
  system.reflection,
  system.runtime.compilerservices,
  system.windows.forms,
  cenginemain in 'cEngineMain.pas' {WinForm.TWinForm: System.Windows.Forms.Form},
  cform in 'FormcForm.pas' {cForm.TWinForm: System.Windows.Forms.Form};

var
  engine: tengine;

//... Compilerzeugs

[stathread]
begin
  engine := tengine.create;

  application.run;
end.


Aber ich hab da noch nicht gewusst, dass ich dann in den einzelnen Units nicht mehr auf Engine zugreifen kann, weil er das nicht findet.

Ich hab die EngineHauptklasse und in der ist schon eine Fensterklasse, welche eine Fenster erstellen soll. Der würde ich als Sender die EngineKlasse mitgeben, aber die Fensterklasse kennt ja nicht TEngine und somit kann ich auch nicht die Funktionen von TEngine aufrufen.

Im Endeffekt ist in TEngine eine Funktion drinne, dass er alles schließen soll. Diese Funktion soll von der Fensterklasse aufgerufen werden, wenn das Fenster geschlossen wird.


Mein kleiner .NET Blog: http://artzuk-interactive.de/

Offline

 

#2 01.10.2005 14:42:40

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: Engine Variable

Nun zunächst die Bemerkung:
Du solltest eigentlich versuchen durch vorrausschauende Planung versuchen ein solches Problem zu vermeiden. (geht nich immer)
Muss z.B. die Fenster-Klasse wirklich die Kontrolle haben? Könnte nicht auch die Engine-Klasse entscheiden wann das Fenster geschlossen werden muss?


Es gibt aber trotzdem Möglichkeiten:

1. Interface
http://www-users.rwth-aachen.de/Martin.Weusten/upload/interface.jpg
Reihenfolge der Deklaration:
1. Interface
2. Fenster
3. Engine

Engine ist von Interface abgeleitet. Fenster bekommt irgendwie einen Pointer auf die Interfaceklasse. Das kann im Konstruktor passieren oder über eine zusätzliche Methode (dein "Sender").
Jetzt kann das Fenster die Methode delete() in Interface aufrufen. Falls nötig kann diese Methode auch in Engine überschrieben werden.

2. Messages
Vom Prinzip genauso, jedoch ist Interface diesmal eine Univerale-Klasse, die eine receive() hat, welche z.B. eine Integer-Konstante akzeptiert. In der von Interface abgeleiteten Klasse Engine kann dann die receive()-Methode so überschrieben werden, dass sie die Integer-Konstante verarbeiten kann.
Vorteil:
Wenn es sehr viele verschiedene Klassen gibt, die alle miteinander "reden" sollen.
Nachteil:
Vergleichsweise langsam, da die Konstante erst ausgewertet werden muss. Für Dinge die nicht häufig passieren (z.B. Hauptfenster schließen) aber durchaus ausreichend.

2. Kontrolle von außen
http://www-users.rwth-aachen.de/Martin.Weusten/upload/interface2.jpg
Eigentlich genau andersherum wie eben, dieses mal wieder das Fenster abgeleitet.
Reihenfolge der Deklaration:
1. BaseFenster
2. Engine
3. Fenster
4. Factory
Nachteil ist eben, dass man irgendeine zusätzliche Klasse benötigt, die Engine erzeugen kann.
=> nicht alzu gute Lösung

Es gibt aber sicher noch mehr Möglichkeiten...

Coolcat


My software never has bugs. It just develops random features.

Offline

 

#3 01.10.2005 17:43:19

artzuk
GodlikeMember
Ort: Leipzig
Registriert: 24.01.2005
Beiträge: 1164

Re: Engine Variable

Zitat:

Muss z.B. die Fenster-Klasse wirklich die Kontrolle haben? Könnte nicht auch die Engine-Klasse entscheiden wann das Fenster geschlossen werden muss?

Das muss so sein, damit die Engine und alle dranhängenden Klassen richtig freigegeben werden können, wenn man auf das x vom Fenster klickt.
Zudem muss auch die Fensterklasse die Hauptschleife der Engine aktivierem, sobald es angezeigt wird. Bei Engine.Create kann ich das leider nicht gleich reinmachen, weil da noch nicht Application.Run aufgerufen wurde.

Zitat:

Engine ist von Interface abgeleitet. Fenster bekommt irgendwie einen Pointer auf die Interfaceklasse. Das kann im Konstruktor passieren oder über eine zusätzliche Methode (dein "Sender").

Genau das ist ja irgendwie mein Problem. Die Unit, wo ich das Fenster deklariere, kennt die Klasse nicht. Und bei Uses kann ich auch nicht 2 Units überkreuzen.
Die Engine muss die Fensterklasse kennen, ist ja klar. Aber um einen Pointer wieder zurück zur Engine zu bekommen, muss auch die Fensterklasse die Engineklasse kennen.


Mein kleiner .NET Blog: http://artzuk-interactive.de/

Offline

 

#4 01.10.2005 18:20:02

LarsMiddendorf
ProMember
Registriert: 24.01.2005
Beiträge: 103

Re: Engine Variable

Zitat:

Die Engine muss die Fensterklasse kennen, ist ja klar. Aber um einen Pointer wieder zurück zur Engine zu bekommen, muss auch die Fensterklasse die Engineklasse kennen.

Das Problem kann man immer lösen, indem man von beiden Klassen jeweils eine abstrakte Basisklasse anlegt, oder noch besser ein Interface mit den Funktionen die der andere Teil jeweils benötigt und dann diese Interfaces/Basisklassen in eine separate Unit legt.

Oder: Im Implementations-Uses dürfen sich auch die Bezüge überkreuzen. D.h. man kann dann den Sender im Implementationsteil auch von TObjekt auf die wirkliche Klasse casten. Diese Variante ist aber unschön.

Allgemein sollte man solche Abhängigkeiten aber wenn es geht vermeiden und sie deuten, wie schon gesagt, manchmal auf einen Fehler im Design hin. Das die anderen Klassen auf die globale Variable Engine zugreifen können ist generell nicht der richtige Weg, sondern man kann ihnen beim Erstellen einen Zeiger auf die Engine geben.

Offline

 

#5 01.10.2005 18:27:55

Coolcat
ProGuru
Ort: Aachen, NRW
Registriert: 24.01.2005
Beiträge: 2780
Web-Seite

Re: Engine Variable

Zitat:

Die Unit, wo ich das Fenster deklariere, kennt die Klasse nicht.

Ja, aber diese Unit kann das Interface kennen! Das ist ja gerade der Trick wink
Du gibst dem Fenster einen Pointer auf die Engine. Dieser ist aber zum Typ Interface gecastet, daher kann das Fenster etwas damit anfangen...

Coolcat


My software never has bugs. It just develops random features.

Offline

 

#6 01.10.2005 19:47:57

artzuk
GodlikeMember
Ort: Leipzig
Registriert: 24.01.2005
Beiträge: 1164

Re: Engine Variable

Zitat:

Das Problem kann man immer lösen, indem man von beiden Klassen jeweils eine abstrakte Basisklasse anlegt

Das habe ich bereits probiert. Ich habe mir ne Unit angelegt, wo ich alle Klassen schon mal vordefiniert hab.
Macht man das so hier

Code: delphi

type
  tengine: class
  end;

  tform: class
  end;


Irgendwie glaub ich, dass das falsch ist. Denn hier kennt er dann kein .MainLoop mehr. (!Das hier lasse ich auf keinen Fall so, weil es nicht mal richtig funktioniert. Das .MainLoop mach füg ich woanders ein, sobald die FensterKlasse nen Pointer auf die Engine hat. Dient hier nur zur Veranschaulichung! smile )

Code: delphi

begin
  engine := tengine.create;
  engine.mainloop;

  application.run;
end.




Zitat:

oder noch besser ein Interface mit den Funktionen die der andere Teil jeweils benötigt und dann diese Interfaces/Basisklassen in eine separate Unit legt.

Hast du ein Beispiel hierfür - also für das Interface mit den Funktionen. Mir fehlt da gerade das Verständnis.


Mein kleiner .NET Blog: http://artzuk-interactive.de/

Offline

 

#7 01.10.2005 20:15:26

LarsMiddendorf
ProMember
Registriert: 24.01.2005
Beiträge: 103

Re: Engine Variable

So in etwa könnte das aussehen( jeder Block eine unit):

Code: delphi

iengine = interface
  procedure xyz();
end;

iengineform = interface
 procedure abc();
end;



Und dann bei den Klassen

Code: delphi

interface

tengine = class(iengine)
  mainwindow:iengineform;
  procedure xyz();
  procedure createmainwindow;
end; 

implementation

uses formxyz;

procedure tengine.createmainwindow
begin
 mainwindow:=tform1.create(self);
end;


Code: delphi

tform1 = class(tform,iengineform)  
  procedure abc();
  constructor create(iengine engine);
end; 



Die Interface sind in Delphi leider etwas verschandelt, weil sie immer automatisch Referenzzählung haben. Außerdem sollte es bei einer modernen Sprache eigentlich egal sein, in welcher Reihenfolge man die Klassen deklariert. Bei Chrome kann man z.B. in jeder Reihenfolge auch mit Kreuzverweisen einbinden und in C# sowieso. Aber mit den Interface ist es am elegantesten.

Offline

 

#8 02.10.2005 13:44:45

artzuk
GodlikeMember
Ort: Leipzig
Registriert: 24.01.2005
Beiträge: 1164

Re: Engine Variable

Ah perfekt - jetzt funktioniert alles wunderbar.

Das mit den interfaces kannte ich noch gar nicht.
Ich sollte mal ne Nachhilfestunde in Sachen Delphi nehmen - ich stolpere immer öfter über Wörter, die was mit Delphi zu tun haben und ich dennoch noch nie gehört hab. War vielleicht doch nicht so gut in meiner Vergangenheit Delphi einfach nur durch Probieren und Befehle in der DelphiHilfe nachschlagen zu erlernen.  yikes


Mein kleiner .NET Blog: http://artzuk-interactive.de/

Offline

 

#9 02.10.2005 15:39:43

artzuk
GodlikeMember
Ort: Leipzig
Registriert: 24.01.2005
Beiträge: 1164

Re: Engine Variable

Ich habe gerade noch ein Problem. Ich möchte der KameraKlasse einen Pointer aufs Device geben.
Dazu hat die KameraKlasse ein Pointer auf die Engine und diese hat eine Funktion, die das Device zurück gibt.

Code: delphi

function tengine.getdevice: device;
begin
 result := fdevice.dev;
end;


FDevice.Dev ist das hier

Code: delphi

private
 fdevice: device;
public
 property dev: device read fdevice;


Und hier kommt der Fehler (letzte Zeile)

Code: delphi

constructor tcamera.create( senderasengine: iengine );
begin
 inherited create;

 // (get) Engine & Device
 fpengine := iengine;
 fpdevice := fpengine.getdevice;



Es ist eine "System.NullReferenceException" .. ich vermute, dass da einfach etwas nil ist.

Es gibt da diese Funktion

Code: delphi

device.create(punk: ^idirect3ddevice9)


Ich vermute damit muss ich den Pointer auf das Device erstellen.
Aber die Funktion bekomme ich nicht zum Kompilieren.
Mit @ etc kann ich nicht arbeiten, weil das "unsafed code" ist und das nicht erlaubt ist und somit auch nicht kompiliert wird.


Mein kleiner .NET Blog: http://artzuk-interactive.de/

Offline

 

#10 03.10.2005 19:01:39

artzuk
GodlikeMember
Ort: Leipzig
Registriert: 24.01.2005
Beiträge: 1164

Re: Engine Variable

Ok das mit den Device hab ich gelöst - der hat scheinbar was dagegen gehabt, dass ich das Device um so viele Ecken jage big_smile


Mein kleiner .NET Blog: http://artzuk-interactive.de/

Offline

 

#11 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#12 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#13 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#14 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#15 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#16 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#17 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#18 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#19 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#20 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#21 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#22 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#23 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

#24 04.10.2005 07:32:43

Guest
Gast

Re: Engine Variable

Aber so wie du es jetzt benutzt, wenn du IEngine wieder auf Engine castest, brauchst du das Interface gar nicht. Da kannst du statt IEngine auch einfach Object schreiben.

 

Brett Fußzeile

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson