Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: So Jul 13, 2025 05:32

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Eventhandler
BeitragVerfasst: Sa Dez 23, 2006 15:54 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Und wiedermal eine Frage an die alten Hasen.
Ich bin nun dabei mein Projekt etwas auszubauen, und dachte mir, dass es doch ganz schön wäre, nen Eventhandler zu baun.

Das ganze soll am ende folgendermaßen funktionieren:
Ich habe eine Klasse zb TEventObject, die schon alle wichtigen Events mitliefert (Onactive, Ondestroy, onmouseup, -move, -down, onkeypressed, usw. usw.)
Dann leite ich davon zb ein Object TMyButton ab, und dann kann ich von da an die Events MyButton.OnMouseDown abfragen. Praktisch genauso, wie es die Delphiumgebung bietet, eben nur für ein GUI

Da ich leider 0 ahnung habe, wie man an so etwas am besten herangeht, wäre es sehr nett, wenn da mal irgendwer nen link zu nem tut (glaube allerdings nicht, dass es sowas ueberhaupt gibt) schicken könnt, oder eine kurze Zusammenfassung, wie man da beginnt, oder ein paar codesegmente, falls ihr selber sowas schon gemacht habt, oder oder oder

Ich habe mir mal den Eventhandler von XD angesehen und der is mir doch etwas zu komplex, als dass ich den Punkt bestimmen könnte, wo ich starten müsste ^^


Vllt hat ja wer von euch ideen
Danke schonma im voraus


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Dez 24, 2006 00:30 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Hallo,
ich versuche grade so etwas beschreiben und zwar hier: http://wiki.delphigl.com/index.php/DGLGUI_Pflichtenheft, besonders interessant ist der Punkt "Entwicklerprozesse (Prozesse des GUI)"

Im Prinzip ist es so, dass Du Deinem TEventObject eine Variable gibst, die ein Methodenzeiger ist.

Zuerst definierst Du den Methodenzeiger:

Code:
  1. TKeyDownEventMethod = Procedure(AKeyDownData: TKeyDownData) Of Object;


Wie Du das aufbaust, ist allein Deine Sache: Du kannst in dem "AKeyDownData" alles mitgeben, was Du Dir wünscht, Du musst Dir nur klar sein, dass Du damit eine Art "Standard" für dein Programm definierst: Auch der Benutzer Deiner GUI muss sich dran halten (so wie in Delphi, die automatisch erzeugten Eventhandler). In das "AKeyDownData" packst Du einfach das, was Du brauchst, also bei KeyDown den TastenCode, den Shiftstatus und so weiter.

Und dann im TEventObject definierst Du:

Code:
  1. TEventObject = Class(TObject)
  2.    FOnKeyDown:  TKeyDownEventMethod;   // Methodenzeiger fürs Hauptprogramm
  3.    Procedure Event_OnKeyDown(AKeyDownData: TKeyDownData);   // Eigener Eventhandler
  4.    .....
  5. End;


Ob das FOnKeyDown eine private Variable ist, die in ein Property verpackt ist, oder einfach eine public Variable, die man einfach so von außen ändern kann, hängt einfach nur von Dir und Deinen Wünschen ab (die published Properties braucht man für den Objekt-Inspektor).

Das Programm, das Deine GUI benutzen möchte, "stöpselt" dann seine Methode, die er anlässlich eines Tastendrucks ausführen möchte, an Deinen Methodenzeiger dran. Angenommen, wir gehen den leichtesten Weg und implementieren das FOnKeyDown als Public Variable, dann sieht das so aus:

Code:
  1. MyEventObject:= TEventObject.Create;
  2. MyEventObject.FOnKeyDown:= MyOwnEventHandler;


In Deinem Hauptprogramm musst Du dann eine Eventhandler-METHODE einrichten, die sich nach dem Standard "TKeyDownEventMethod" richten muss:
Code:
  1. Procedure MyOwnEventhandler(AKeyDownData: TKeyDownData);



Das ganze geht dann so:

1) Benutzerereignis abfangen (wie auch immer, ich machs mit SDL)
2) Anschauen, was man gefangen hat, Daten aufbereiten und in "AKeyDownData" stopfen
3) Wenns z.B. ein KeyDown ist: TEventObject.Event_OnKeyDown(AKeyDownData: TKeyDownData) aufrufen
4) Jetzt hat das TEventObject.Event_OnKeyDown Gelegenheit, was Eigenes zu tun, zeichnen zum Beispiel
5) Am Ende der Methode Event_OnKeyDown musst Du das TEventObject.FOnKeyDown(AKeyDownData) aufrufen, damit rufst Du EIGENTLICH den Eventhandler des Hauptprogramms auf, denn jetzt ist er dran.


Das Event fährt (sozusagen wie ein Blitz) in Dein TEventObject und direkt durch den Methodenzeiger FOnKeyDown in die Methode MyOwnEventhandler des Hauptprogramms.

Das TEventObject dient sozusagen als "Datenleitung".

Traude


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Dez 24, 2006 00:35 
Offline
Guitar Hero
Benutzeravatar

Registriert: Do Sep 25, 2003 15:56
Beiträge: 7810
Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Google mal im Netz nach "Function Pointer" und "Callback" bzw. Tutorials dazu. Dann wird dir bestimmt ein Licht aufgehen. (zum 4. Advent ;) )

_________________
Blog: kevin-fleischer.de und fbaingermany.com


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Dez 24, 2006 15:14 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Hi Danke ma fuer eure Antworten. Ich habe mir nochma die XDEngine angesehen und versucht, das was dort drinnen stand, zu verstehen und umzusetzen.

Ich verfahre nun so, wie es Traude in etwa beschrieben hat.
Code:
  1. constructor TEventManager.Create;
  2. begin
  3.   inherited;
  4.   LIdle       := TList.Create;
  5.   LQuit       := TList.Create;
  6.   LActive     := TList.Create;
  7.   LKeyDown    := TList.Create;
  8.   LKeyUp      := TList.Create;
  9.   LMouseDown  := TList.Create;
  10.   LMouseUp    := TList.Create;
  11.   LMouseMove  := TList.Create;
  12.   LResize     := TList.Create;
  13.   LRedraw     := TList.Create;
  14. end;

Hier erstelle ich die Listen, in denen alle Events registriert werden.
Ein button, der ein OnClick bekommen soll, wird per AddMouseDown in die LMouseDown eingefuegt.

Hier mal ein Beispiel, wie ich die Geschichte benutze:
Code:
  1. type TTest = class(TeasySdl)
  2.   procedure DrawScene; override;
  3.   procedure HandleMousePressed(Event:TSDL_MouseButtonEvent); override;
  4.   end;
  5.  
  6. var mytest: TTest;
  7.     gui: TQuadric;


Code:
  1. begin
  2.   mytest := ttest.Create('www.delphigl.com .:. Lesson 2','particle.png');
  3.   mytest.Start;
  4.   gui := TQuadric.Create(100,100,100,100);
  5.   eventmanager.AddMouseDown(POINTER(gui),gui);
  6.   Eventmanager.Start;
  7.   mytest.Loop;
  8.   mytest.Stop;
  9. end.


TQuadric ist nur eine Klasse mit den Attributen Top, Width, Height und Left und den Methoden Create, Draw, OnClick und Destroy.

Ich erstelle also das Object Gui und registriere es dann in meinem Manager.
Die AddMouseDown sieht folgendermaßen aus:
Code:
  1. function TEventManager.AddMouseDown (P:Pointer; Obj: TObject) : Pointer;
  2. var Data: PListData;
  3. begin
  4.   if not Assigned(lMouseDown) then lMouseDown:=TList.Create;
  5.   New(Data);
  6.   Data.P    := P;
  7.   Data.Obj  := Obj;
  8.   LMouseDown.Add(Data);
  9. end;


Danach starte ich den manager:
Code:
  1. procedure TEventManager.Start;
  2. begin
  3.   with Events do
  4.   begin
  5.     OnIdle      := OnIdle;
  6.     OnQuit      := OnQuit;
  7.     OnActive    := OnActive;
  8.     OnKeyDown   := OnKeyDown;
  9.     OnKeyUp     := OnKeyUp;
  10.     OnMouseDown := OnMouseDown;
  11.     OnMouseUp   := OnMouseUp;
  12.     OnMouseMove := OnMouseMove;
  13.     OnResize    := OnResize;
  14.     OnRedraw    := OnRedraw;
  15.  
  16.     HandleEventMsg;
  17.   end;
  18. end;

Und da Tritt in der OnIdle := Onidle zeile schon ein Fehler auf. Die Konsole meldet ein EAccessViolation nur erstellt sind die Listen im Grunde ja vorher schon, durch das Create des Eventmanagers. Der Eventmanager wird hierbei im Create von TTEst mit aufgerufen:
Code:
  1. constructor TEasySDL.Create(const Caption, Icon: String);
  2. begin
  3.   fWindowCaption := Caption;
  4.   fWindowIcon := Icon;
  5.  
  6.   fScreenWidth := DEFAULT_WINDOW_WIDTH;
  7.   fScreenHeight:= DEFAULT_WINDOW_HEIGHT;
  8.  
  9.   Seconds := 0;
  10.   FPSDraw := TRUE;
  11.   InitializeGlobals;
  12. end;

Code:
  1. procedure InitializeGlobals;
  2. begin
  3.   BugTracker := TBugTracker.Create('LogFile.txt');
  4. (***** BugTracker initilasieren ***********************************************)
  5.   BugTracker.AddBugReport('*************** BugTracker ***************');
  6.   BugTracker.AddBugReport('==========================================');
  7.  
  8. (***** Textures initilasieren *************************************************)
  9.   TextureManager := TTextureManager.Create();
  10.  
  11. (***** Fonts initilasieren ****************************************************)
  12.   FontManager := TFontManager.Create();
  13.   FontManager.AddFont('Fonts/Impact.ttf','1',15,$7F,$99,$B2,0);
  14.   FontManager.AddFont('Fonts/Arial.ttf','FPS',15,$7F,$99,$B2,0);
  15.  
  16. (***** Selections initilasieren ***********************************************)
  17.   SelectionManager := TSelectionManager.Create();
  18.  
  19. (***** Selections initilasieren ***********************************************)
  20.   SceneManager := TSceneManager.Create();
  21.  
  22.   SceneManager.AddScene(S_STARTSCENE,TStartScene.Create);
  23.   SceneManager.AddScene(S_DEBUG1SCENE,TDebug1Scene.Create);
  24.   SceneManager.SetScene(S_STARTSCENE);
  25.  
  26.   EventManager := TEventManager.Create();
  27. end;


Wie gesagt bis zu der OnIdle zuweisung geht es fehlerfrei durch und dann kommt die Exception


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Dez 26, 2006 13:05 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Hallo Shaddow,

Code:
  1. with Events do
  2. begin
  3.    OnIdle := OnIdle;
  4.    OnQuit := OnQuit;
  5.    ...
  6. End;


Ich verstehe nicht ganz was der dieser Code macht. Was sind die Variablen "Events", "OnIdle", etc. genau? Denn es sieht mir nicht aus, als ob Du mit der Anweisung


Code:
  1. With Events Do OnIdle := OnIdle;


etwas zuweist, sondern Du weist der Variable "OnIdle" wieder den Inhalt der Variable "OnIdle" zu. Und wenn vorher nichts drin war ist auch nacher nichts drin.
Traude


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Dez 26, 2006 13:46 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Jop das war einer der Fehler. Inzwischen gehts bei mir
Das Prob war, dass Onidle ne Procedure ist und Events.Onidle eine Variable/Zeiger auf eine Procedur.
Weil ich Events ncih dauernd davor schreiben wollte, hab ichs mitm With do gemacht, aber dabei vergessen, dass
Code:
  1. with Events do
  2.   Onidle := OnIdle
  3. end;

das selbe ist wie
Code:
  1. Events.OnIdle := Events.OnIdle

Ich wollte aber
Code:
  1. Events.Onidle := OnIdle haben.


So hab ichs geschrieben und nach der Ausmerzung der restlichen fehler gehts nun ^^


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 28, 2006 01:13 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Habe jetz mal alles noch mal neu aufgezogen und hier ist das entstandene für ein KeyDownEvent

Code:
  1.  
  2. type
  3.   pProcedureKeyPress      = Procedure (Key: Word);
  4.   pEventData              = ^TEventData;
  5.   TEventData              = record
  6.                               P: Pointer;
  7.                               Obj: TObject;
  8.                             end;
  9.  

[später ist dann OnKeyDown : pProcedureKeyPress;

ich registriere also eine prozedur fuer das keydownevent:
Code:
  1.  
  2. procedure    AddKeyDown      (P: Pointer; Obj: TObject = nil);
  3. var Data : pEventData;
  4. begin
  5.   New(Data);
  6.   Data.P := P;
  7.   Data.Obj := Obj;
  8.   LKeyDown.Add(Data);
  9. end;
  10.  


Das KeyDown event des SDL_pollEvent ruft dann folgendes auf:
Code:
  1. procedure OnKeyDown     (Key : Word);
  2. var i : Integer;
  3.   test : PeventData;
  4.   proc : pObjProcedureKeyPress;
  5. begin
  6.   if not Assigned(EventManager.LKeyDown) then
  7.   begin
  8.     raise TSE_EventManagerFail.Create('LKeyDown not Assigned');
  9.     Exit;
  10.   end;
  11.   with EventManager.LKeyDown do
  12.   begin
  13.   writeLn('>>>>'+inttostr(count-1));
  14.     for i := 0 to Count-1 do
  15.     begin
  16.       test := Items[i];
  17.       if not Assigned(pEventData(test).Obj) then
  18.       begin
  19.         WriteLn('1');
  20.         pProcedureKeyPress(pEvenTData(test).P)(Key);
  21.       end
  22.       else
  23.       begin
  24.         WriteLn('2');
  25.         TMethod(proc).Data := pEvenTData(test).Obj;
  26.         TMethod(proc).Code := pEvenTData(test).P;
  27.         proc(key);
  28.       end;
  29.     end;
  30. //      pProcedureKeyPress(Items[i])(Key);
  31.   end;
  32. end;


Die Writelns usw. dazwischen sind nur zum debuggen gedacht.
naja das prob ist einfach, dass das ganze zwar bei einer procedure, die cih registriere (wo obj beim Adden also nil ist), super geht nur bei einer klasse kommt dauernd beim registrieren ein fehler

Bsp:
Code:
  1. EM.AddKeyDown (@ww,camera);

Camera ist halt das objekt und es kommt dauernd der fehler:
Variable erforderlich..
ka was das soll


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 28, 2006 14:51 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Hallo Shaddow,
ich kann Dein Problem nicht nachvollziehen. Kann kein CompilerFehler sein, denn bei mir gehts durch. Dann ist das ein Laufzeitfehler? Und bei welcher Zeile stürzt er ab?
Traude


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 28, 2006 15:05 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Es IST ein Compilerfehler:
Bild


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 28, 2006 15:23 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Ach so.

Du möchtest die Kamera im EventHandler registrieren und machst das im Constructor der Kamera. Du musst bedenken, was das heißt:

Der Kamera-Konstruktor kennt Deine Instanz "camera" ja gar nicht. Wo soll er die hernehmen? Du müsstest im Kamera-Konstruktor bei der Methode "EM.AddKeyDown (@ww,camera); " statt "camera" zumindest "Self" eintragen. Aber ich bin mir gar nicht sicher, ob das funktioniert, denn ich glaube die Variable TCamera.Self existiert erst, NACHDEM der Konstructor TCamera.Create fertig ist. Aber da bin ich mir, wie gesagt, nicht sicher
Traude

@edit: hab gerade nochmal nachgesehen: Delphi-Hilfe, Stichwort "Self, Klassenmethoden":
Zitat:
In der definierenden Deklaration einer Klassenmethode kann mit dem Bezeichner Self auf die Klasse zugegriffen werden, in der die Methode aufgerufen wird


Das heisst es sollte funktionieren, wenn Du bloss "camera" durch "Self" ersetzt.


Zuletzt geändert von Traude am Do Dez 28, 2006 15:49, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 28, 2006 15:24 
Offline
DGL Member

Registriert: Sa Okt 22, 2005 20:24
Beiträge: 291
Wohnort: Frauenfeld/CH
probier mal bitte ein @@ww aus... ich glaube dann wird das ganze zu einem pointer. bin mir aber nicht sicher.

_________________
bester uo-shard: www.uosigena.de


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 28, 2006 16:08 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Weder self noch @ aendern die fehlermeldung :)

der fehler wurde nun in form einer art gemeinschaftsarbeit geloest:
EventManager.AddKeyDown (@TSE_Camera.ww,Self);
das tse_camera hat gefehlt obwohl ich das eigentlich scho getestet hatte ^^ vllt war da ein anderer feholer dabei


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 28, 2006 16:59 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Ich habs mir runtergeladen und kompiliert:


Code:
  1. constructor TSE_Camera.Create (NWidth, NHeight: Integer; NNearClipping, NFarClipping: Single);
  2. Type TKeyEvent = Procedure (Key: Word);
  3. Var abc: TKeyEvent;
  4.       MyPointer: Pointer;
  5. begin
  6.   inherited Create;
  7.   fWidth        := NWidth;
  8.   fHeight       := NHeight;
  9.   fNearClipping := NNearClipping;
  10.   fFarClipping  := NFarClipping;
  11.   //EventManager.AddKeyDown (@ww,camera);  // geht nicht
  12.   //EventManager.AddKeyDown (abc,camera);  // geht nicht
  13.   EventManager.AddKeyDown (MyPointer,camera);  // das geht
  14. end;


Der Frage, warum er hier eine Variable "camera" kennt, bin ich nicht weiter nachgegangen, aber er kennt sie.

Er wollte beim kompilieren hier einen untypisierten Pointer haben. Und offensichtlich ist ein Prozedurzeiger was anderes als ein untypisierter Pointer. Aber Achtung: ein Ein Prozedurzeiger ist auch was anderes als ein Methodenzeiger. Delphi ist hier stur bei den übergebenen Parametertypen.
Traude


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Dez 28, 2006 17:03 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Nen Untypisierten Zeiger bekommt man ja, indem man noch ein @ voranstellt. also etwas ala @@ww. Aber das werd ich nachher erst testen können


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 14 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 13 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.016s | 15 Queries | GZIP : On ]