Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Betrifft: PasGUI, Thema: Wie kommt ein GUI-Item zu seinem Event?
Als Vorinformation: ich arbeite an einer GUI - immer noch.
Derzeit mache ich das Finden der Events grundsätzlich anders als die VCL. Die Lösung, die ich derzeit habe, ist nur eine Möglichkeit, die mir eingefallen ist, weil ich sowohl Methoden als auch Prozeduren/Funktionen als Eventhandler zulassen wollte. Sie ist implementiert und läuft auch, ich brauche also keine Tipps, wie man das macht. Was ich jetzt bräuchte, wären ein paar Argumente dafür oder dagegen, oder vielleicht Vorschläge, wie man es anders machen sollte. Dafür habe ich versucht, die Vor- und Nachteile herauszuarbeiten:
---------------------------------------------------------------------------------------------------------------------------------------------
VCL-Beschreibung:
Die VCL hält ihre Events als Methoden des jeweiligen Fensters. Beim Speichern der Komponenten werden meines Wissens die Namen der Eventhandling Routinen per RTTI gespeichert und beim Laden können diese Routinen mit diesem Namen im jeweiligen TForm wieder aufgefunden werden.
Vorteile:
1) Ein sehr klarer struktureller Aufbau: das TForm ist für alles zuständig
2) Die Events können vom TWriter/TReader gut aufgefunden werden
3) Der Programmierer ist von jeder zusätzlichen Tipparbeit befreit, weil alles automatisch erledigt werden kann
Nachteile:
1) Es kommen nur Methoden als Eventhandler in Frage.
2) Man kann in einem Delphi-VCL-Programm das Hauptprogramm (*.dpr) nicht in Delphi selbst editieren. Das mag kein schwerwiegender Grund sein, aber es stört mich.
---------------------------------------------------------------------------------------------------------------------------------------------
PasGUI-Beschreibung:
Die PasGUI ist ein Baum und hat wie jeder Baum ein Root. Mein Root besitzt eine Liste, die Datensätze mit folgendem Inhalt enthält:
* Identität des GUIItems (ein Name),
* Typ des Events,
* ein Zeiger auf die Eventhandling Routine.
Anläßlich der Erzeugung eines GUI-Items holt es sich seine Events aus dieser Liste ("Mein Name ist BlaBla", "Hast Du ein Key-Down-Event für mich?",*steckt den Key-Down-Event-Zeiger in seinen Key-Down-Slot*)
Vorteile:
1) Im Gegensatz zur VCL ist bei einem Programm, das ausschließlich mit der PasGUI arbeitet, das Hauptprogramm wieder benutzbar.
2) Es können sowohl Methoden als auch Prozeduren/Funktionen als Eventhandler verwendet werden.
3) Die Liste der Eventhandler ist auch gut auffindbar, könnte zwar auch mit RTTI arbeiten, aber das ist gar nicht nötig
Nachteile:
1) Die Root-Liste muss vom Programmierer aufgebaut werden, das ist zusätzliche Tipparbeit.
2) Der Aufbau ist nicht von vornherein so klar wie bei der VCL, denn Eventhandling Routinen können sich sowohl im Hauptprogramm als auch in anderen Units befinden
3) Man muss sich umgewöhnen, weil es anders ist als die VCL
2) Man kann in einem Delphi-VCL-Programm das Hauptprogramm (*.dpr) nicht in Delphi selbst editieren. Das mag kein schwerwiegender Grund sein, aber es stört mich
Was hat das Hauptprogramm mit deinen Formulardaten zu tun? Außerdem kann man das einfach mit "Projekt|Quelltext anzeigen" anzeigen und bearbeiten. Die Formulardaten werden in der unitname.dfm gespeichert. Dabei werden die in der dfm gespeicherten Methodennamen des Formulars mittels RTTI den methoden des Forms zugeordnet.
Geht es dir bei diesem Verfahren nur um die (De)serialisierung der komponenten, oder auch um die Veränderung zur Runtime?
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Es geht mir einzig und allein darum, zu erfahren, was Ihr für die bessere/geeignetere Methode anseht, wie Events geholt werden. Was ich nicht so gerne hätte, wäre, wenn man mir sagt: machs doch einfach so wie die VCL, ohne das zu begründen.
@Serialisieren: Die GUI ist eine Art Reizleiter-Nervensystem. Deshalb muss sie die Events(= die Endpunkte des Nervensystems) irgendwo finden können, egal ob es jetzt ums Laden/Speichern geht oder nicht. RTTI kann das, weil vorbestimmt ist, dass die Events Methoden des TForm sein müssen. Aber das ist nicht die einzige vorstellbare Möglichkeit. Ich verwende im Augenblick eine andere, die auch funktioniert (siehe obige Beschreibung).
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Also wenn ich das richtig verstanden habe, dann sind die beiden Möglichkeit nicht wirklich unähnlich, oder? So lange es funktioniert sehe ich da keine Probleme. Und dann ist das ja alles okay. Natürlich vorrausgesetzt der Programmierkomfort stimmt. Wenn es dadurch um ein vielfacheres komplizierter oder verwirrender wird wäre das ja nicht so schön. Dann wäre das evtl. etwas wo man schauen sollte ob man da nicht anders machen kann.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Doch, sie sind sehr unähnlich.
In der VCL macht das der Objektinspektor, man trägt eine Prozedur in eine Liste ein. Mit Sourcecode wird der User hier gar nicht belästigt. Ich habe aber keinen Editor für die GUI. Daher sieht das bei mir ein wenig gewöhnungsbedürftig aus:
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Also ich würde spontan mal sagen, dass es okay aussieht.
Wobei da aber das übliche Problem der Software Entwicklung wieder zum Tragen kommt. Ob es wirklich alles so funktioniert und so praktisch ist wird man erst dann richtig sehen, wenn man es in einer komplexen Anwendung benutzt und es sich bewehrt hat. Aber das ist ja irgendwie leider immer so.
Aber eines wundert mich gerade doch noch. Für Proceduren hast du ProcToEvent. Für Methoden hast du aber KeyEventToEvent. Da hätte ich eher so etwas wie MethodToEvent erwartet. Oder gibt es dort für jeden Methodentypen eine Konvertierfunktion?
Was evtl. auch verwirrend sein könnte. ProcToEvent bekommt einen Pointer wärend KeyEventToEvent, so schneint mir, eine "procedure of object" bekommt. Das mag vielleicht etwas verwirrend sein. Mal pointer mal richtiger typ.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Warum es für Methoden und Prozeduren verschiedene Arten des Verpackens gibt:
Du wirst es mir vielleicht nicht glauben, aber ich weiß es nicht mehr. Das System ist schon relativ groß geworden, und ich muss nachschauen. Ich weiß nur noch, dass ich damals einen Grund hatte, das so zu machen. Ich werden das heute nachmittag verifizieren und nachbessern, wenn es möglich ist.
Ansonsten: wieder danke für die Antwort. Dinge, die man selber gemacht hat, kann man nicht selber bewerten.
NACHTRAG:
Zitat:
Was evtl. auch verwirrend sein könnte. ProcToEvent bekommt einen Pointer wärend KeyEventToEvent, so schneint mir, eine "procedure of object" bekommt. Das mag vielleicht etwas verwirrend sein. Mal pointer mal richtiger typ.
Meines Wissens geht das nicht anders. Man kann einen normalen Zeiger auf eine Prozedur haben, aber eine Methode ist intern ein Datensatz, der aus zwei Pointern besteht. Ich kenne keine Möglichkeit, einen Pointer auf eine Methode zu setzen, denn damit erwischt man den zweiten Pointer nicht. Man kann nur einen Pointer auf TMethod setzen, erst damit hat man die Methode wirklich "im Griff".
Wenn die GUI Items diese Liste abfragen, um sich ihre Eventhandler zu holen, dann setzen sie bei den Prozeduren sich selbst als Objekt ein. Sie "annektieren" damit die Prozedur:
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Also Methoden haben neben den Parametern noch einen Pointer auf Self. Also dass es da einen Unterschied gibt und entsprechend 2 unterschiedliche Methoden ist ein muss und auch vollkommen okay. Mich irritiert nur der Name, der sugeriert, dass es da noch mehr Varianten von gibt. Bzw das es auf der einen Seite Pointer und auf der anderen Seite echte Typen sind.
PS: Och keine Sorge. Ich weiß auch häufig genug nicht mehr warum ich das mal so oder so gemacht habe.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Zitat:
Mich irritiert nur der Name, der sugeriert, dass es da noch mehr Varianten von gibt.
Ja Du hast recht, es gibt da noch mehr Methoden. Und ich muss nachsehen, ob das wirklich seine Berechtigung hat und nicht anders geht.
Aber eines find ich toll: ich habe mich wirklich ungeheuer bemüht, sowohl sprechende Namen zu vergeben als auch stringent zu sein. Nachdem Du das offensichtlich auf den ersten Blick gesehen hast, dass es hier mehrere Varianten gibt, ist mir das anscheinend auch gelungen.
Wieso nimmst du nicht normale Methodenproperties wie die VCL, und bietest eine Procedure to ProcedureOfObject konvertierung an, die für jeden eventtyp überladen werden muss. Bei der ProcedureOfObject nimmst du dann einen magic value für Objekt den Objektzeiger (z.B. high(Pointer)) der bedeutet dass es eine procedure und keine procedure of object ist.
Ich würde allerdings den Support für Prozeduren gleich ganz weglassen. Der User wird ja wohl in der lage sein ein Dummyobjekt zu erzeugen.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Ich finde das Prinzip garnicht so schlecht. Denn so ein Dummyobjekt ist auch wieder nerverei und dass die Events auch Prozeduren unterstützen, ist eine gute vorbereitung, falls man die GUI als DLL/Shared Object weitergeben möchte.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
@The-Winner: Das ist ja eben mein Problem, dass ich mich nicht entschließen kann. Das mit den Prozeduren schaut umständlich aus, denk ich mir dann. Also doch so wie die VCL? Sowohl die VCL-Methode als auch meine haben Argumente für sich. Aber ich kann mich verflixt nochmal, nicht entscheiden.
Der Grund, warum ich ursprünglich diese Variante genommen habe, hilft auch nicht weiter: ich hatte es mir damals in den Kopf gesetzt es genau NICHT so zu machen wie die VCL. Aber das ist kindisch. Den Ausschlag geben müßte ein Argument. Warum hat sich Borland damals entschieden, es so zu machen? Ich tippe mal darauf, dass es eine elegante Art ist, den Programmierer zu entlasten. Der ursprüngliche Programmaufbau (Hauptprogramm mit darunterliegenden Units) geht aber dabei zum Teufel. Ist das nicht auch ein Argument? Für mich war in Delphi immer das Ding, wo das Hauptformular drinsteckt, das Hauptptogramm. Hab mir nie groß Gedanken drüber gemacht. Bis ich die ersten Programme von Jan Horn gesehen habe.
NACHTRAG: Also ich hab wirklich Alzheimer. Immer überlese ich etwas.
Zitat:
Wieso nimmst du nicht normale Methodenproperties wie die VCL, und bietest eine Procedure to ProcedureOfObject konvertierung an
GENAU das mache ich ja. Ich habe Methodenproperties wie in der VCL. Ich habe aber keinen Objektinspektor, wo man die Methodenproperties einfach befüllen kann. Natürlich kann man in der PasGUI folgendes ganz einfach machen:
Das ist ein Auszug aus dem TGUICustomListBox.SetAlign:
Code:
fScrollBar.OnScroll:= TrackPosition;
Wobei "TrackPosition" eine Listbox-Methode ist, die das tut, was der Benutzer erwartet, wenn an ihrer Scrollbar herumgefummelt wird: sie dreht die Anzeige entsprechend weiter.
Diese Art des Befüllens der Methodenproperties ist verblüffend einfach, hat aber einen Haken: Wie willst Du damit je ein OnCreate-Ereignis auf die Reihe kriegen? In den Konstruktor darf ich nichts stecken, weil die Konstruktoren alle gleich sein müssen. Wenn der Konstruktor seine Arbeit erledigt hat, dann ists aber vorbei mit dem OnCreate. Nun Ist aber OnCreate ein sehr wichtiges Ereignis, wenn nicht DAS wichtigste. Eine GUI, die kein OnCreate-Ereignis bereitstellt, könnte ich mir vermutlich an den Hut stecken.
Aus diesem Grund habe ich jetzt eine Liste, in der die Elemente anläßlich ihrer Erzeugung sich ihre Eventhandler abholen können.
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich hab nicht wirklich die Zeit jetzt den ganzen Thread zu lesen drum entschuldigung, wenn ich was von jemanden wiederholen.
Der Standard für dieses Problem sind eigentlich Observer, observer funktioniert im Prinzip wie das Zeitungsabo.
Der Abonent(ist ein Widget) bestellt ein ABO beim Verleger(registriert sich für ein Event beim EventManager) und der Verleger gibt an allen Abonenten eine neue Zeitungsausgabe(callback aufruf), wenn es neuigkeiten gibt.
Das Prinzip ist in einer sehr schwachen umsetzung ja bei VCL wiederzufinden.
Eine bessere Lösung könnte so aussehen.
Widget hat eine Methode OnKeyChange, im Konstruktor wird OnKeyChange bei einen EventManager registriert.
Jedes Widget sollte einen EventManager haben, damit kann man die rekursive Eventauflösung haben(Form schaut wo Maus geklickt hat und gibt nur an passende Controls das Event weiter, diese Controls fragen die Kinder,...) statt ner lahmen prüfe alle Widgets durch. Dann kann man z.B.OnKeyChange in einen Extra FocusEventManager(einmalig) registrieren und OnMouseDown bei dem Parent.
Der Vorteil ist bei der übersicht und verarbeitung, ein EventManager prüft nur die in seiner Registriert Liste und geht nicht alle Kinder des Widgets durch(iteration und prüfungen sind weniger). Noch dazu braucht man keine RTTI Daten und man sieht auch was passiert(es wird nichts Hinter den Kulissen versteckt). Man kann auch ein Event bei meheren Observern registrieren und mehreren Listener an ein Observerevent binden.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Das mit den Observern ist natürlich ein interessanter Ansatz. Aber Du vermischt m.E. zwei ganz verschiedenen Dinge:
1. Das Fenster kriegt eine Windows Botschaft. Diese Botschaft ethält zusätzliche Info, etwa die Mausposition, einen Tastencode usw. Es enthält jedenfalls keine Information, wen genau diese Botschaft betrifft. Es ist Aufgabe des Fensters, zu wissen, welches Element grade den Fokus hat. Dorthin wird die Botschaft dann geliefert, mögllichst schnell (über den Baum).
2. Wenn das fokussierte Item jetzt die Botschaft kriegt, dann tut es zunächst Dinge wie eine Animation ausführen, um den Benutzer eine visuelle Rückmeldung zu geben aber schließlich ruft es seinen Eventhandler auf. So ein Observer kann vermutlich mehrere Eventhandling Routinen an ein Event binden, die VCL kann nur eines binden (und ich auch).
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Ich habe leider Probleme beim Schreiben der Funktion <<MethodToEvent>>.
Grund: Der Funktion muss ein Eventhandler übergeben werden. Die Funktion selbst macht dann nur eine Typkonvertierung:
Code:
Function NotifyEventToEvent(AEvent: TNotifyEvent): TEvent;
Begin
TMethod(Result):= TMethod(AEvent);
End;
Das ist eine Vorbereitung darauf, die übergebene Methode in eine Liste hängen zu können. Der Haken daran ist, dass der Compiler strikt auf die Einhaltung der Parametertypen besteht. Ich kann daher an die Funktion "NotifyEventToEvent" nur einen Parameter übergeben, der mit einem TNotifyEvent kompatibel ist, nicht aber ein TKeyEvent zum Beispiel. Ich habe im web gesucht und ein paar Workarounds gefunden (z.B. http://www.delphipraxis.net/topic99539.html, ziemlich weit unten im Text), aber ich fand, dass es viel einfacher und auch sicherer ist, für jedes Event einen eigenen Typecaster zu schreiben - so viele Events sind es ja nicht.
Mitglieder in diesem Forum: 0 Mitglieder und 6 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.