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

Aktuelle Zeit: Mo Jul 14, 2025 17:48

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



Ein neues Thema erstellen Auf das Thema antworten  [ 31 Beiträge ]  Gehe zu Seite Vorherige  1, 2, 3  Nächste
Autor Nachricht
 Betreff des Beitrags:
BeitragVerfasst: Do Sep 17, 2009 16:57 
Offline
DGL Member
Benutzeravatar

Registriert: Di Sep 03, 2002 15:08
Beiträge: 662
Wohnort: Hamburg
Programmiersprache: Java, C# (,PhP)
Aber der Pointer muss doch was zurückliefern oder knallt der direkt beim Zugriff?

@irgendwo free() aufrufen: Hört sich sehr ungesund an.

_________________
(\__/)
(='.'=)
(")_(")


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Sep 17, 2009 17:09 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ja, der Pointer enthält die Adresse zum (ehemaligen) Objekt. Da das dort aber nicht mehr ist, ist der Speicher wahrscheinlich nicht mehr alloziiert. Selbst wenn es nicht sofort eine Zugriffsverletzung gibt, sind die Daten doch nicht die richtigen und es wird zu irgendwelchen interessanten Fehlern kommen.

mit "Irgendwo" war gemeint, wenn man ganz allgemein in seinem Programm ein Objekt freigibt.

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy 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


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Sep 17, 2009 20:02 
Offline
DGL Member
Benutzeravatar

Registriert: Di Nov 07, 2006 13:37
Beiträge: 83
Wohnort: Partenheim
Die InterfaceList ignoriere ich deshalb, weil ich nicht nur Objekte eines einzigen Interfaces in der Liste habe.
Ich hänge mal einen Teil des Klassendiagramms mit an, um die Sache deutlicher zu machen. Es geht, wie vermutet, um eine GUI. Das bisher als "IDrawable" bezeichnete Interface ist hier "IPositionable". Und Button ist natürlich von WindowComponent abgeleitet.

Kurze Beschreibung:
BaseComponent bewahrt in seiner Liste ausschließlich Objekte vom Typ WindowComponent auf, da WindowComponent aber ein Abkömmling ist, kennt BaseComponent nicht den WindowComponent, sondern nur BaseComponent.
Jetzt muss ich aber in "OnMouseDown" auf die Position von dem WindowComponent zugreifen, was ich über das Interface "IPositionable" realisieren will, denn das kann der BaseComponent ja kennen.

Wenn sich jetzt einige fragen, warum ich "OnMouseDown" nicht einfach in "WindowComponent" ausformuliere, da es ja ausschließlich WindowComponents betrifft:
Stimmt, aber der WindowObserver braucht exakt dieselbe Implementierung von "OnMouseDown", da er sozusagen der Container aller Component-Wurzeln ist.
Und wer will schon gerne doppelten Code?

Was ist dagegen zu sagen, wenn ich Interfaces, wie vorgeschlagen, nutze und das Reference-Counting austrickse? Wie genau, müsst ihr mir nochmal erklären.
Wozu wurde denn überhaupt so eine halbherzige Garbage-Collection eingebaut?


Vielen Dank schonmal.

Conan


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

_________________
THE TRUTH IS NOT OUT THERE!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Sep 18, 2009 08:18 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Conan hat geschrieben:
Was ist dagegen zu sagen, wenn ich Interfaces, wie vorgeschlagen, nutze und das Reference-Counting austrickse?
Dagegen kann man gar nichts sagen. Gut ist, was nützlich und erfolgsverspechend ist. Wenn Du meinst, dass Du das im Griff hast, warum nicht?

Ich find das echt witzig. Du stehst genau vor demselben Problemen wie ich vor zwei Jahren, nur sieht Dein Code ganz anders aus als meiner.

Zum Beispiel habe ich keine Interfaces verwendet.

Conan hat geschrieben:
Wenn sich jetzt einige fragen, warum ich "OnMouseDown" nicht einfach in "WindowComponent" ausformuliere, da es ja ausschließlich WindowComponents betrifft:
Stimmt, aber der WindowObserver braucht exakt dieselbe Implementierung von "OnMouseDown", da er sozusagen der Container aller Component-Wurzeln ist.
Und wer will schon gerne doppelten Code?
Exakt über dieses Thema hatte ich eine Diskussion mit I0n0s. Ich hatte damals vorgeschlagen, diesen "Observer" (der bei mir anders heißt) einfach vom BasisItem abzuleiten, und das wollte er nicht. Nach viel Hin und Her und umschreiben hat sich für mich Folgendes herausgestellt:

1. Die Prozedur des Basis-Items heißt
Code:
  1. Procedure KeyDown(AKey,PreviousKey: TInt32); Virtual;
und ruft das Event "OnKeyDown" auf. Das war zwingend notwendig, denn häufig muss das Item nicht nur das Event aufrufen, sondern auch selber was tun.

2. Die Prozedur des Observers heißt
Code:
  1. Procedure KeyDown(AReceiver: TuInt32; AKey,PreviousKey: TInt32); Reintroduce;
und musste deshalb mit "Reintroduce" versehen werden, weil es eine Callback-Routine des Operating Systems ist, und dieses muss den Empfänger der Botschaft angeben, damit der Observer auch weiß, welches Fenster es betrifft, denn es kann mehrere Fenster geben.

TObserver.KeyDown unterscheidet sich bei mir vom TGUIItem.Keydown sowohl im Prozedurkopf als auch im Code-Teil der Prozedur. Es ist also gar nicht der gleiche Code. Daher wäre es gerechtfertigt, es neu zu schreiben. Ist aber jetzt nur als Denkanstoß gemeint.



@ Interfaces: Ich habe die GUI so gemacht wie Delphi: Im Basis Item sind alle nötigen Funktionen schon enthalten, aber alles in der Protected-Sektion. Die Descendants ändern dann nur mehr die Sichtbarkeit, definieren also eine geerbte Funktion/Property als Public oder Published, was nicht viel Arbeit ist und gewährleistet, dass Descendants immer die gleiche Routine verwenden. Es ist gar nicht so einfach, jetzt herauszuarbeiten, worin sich das von den Interfaces unterscheidet, denn beide Methoden wollen das Gleiche aber erreichen es auf verschiedenen Wegen.

Wenn ich z.B. das Positionieren meiner ganzen GUI umstellen möchte, ändere ich die Prozedur des Basis-Items, und das wars auch schon. Tricksereien sind gar nicht notwendig.

Beim Rendern ist es anders. Das BasisItem darf - wenn überhaupt - gerade mal den Hintergrund rendern. Jedes Item muss klarerweise eine eigene Rendering-Procedure haben, denn eine Listbox rendert natürlich anders als ein Button. Ist auch nicht grade der typische Fall für Interfaces.

Viele Grüße
Traude


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Sep 18, 2009 10:28 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 05, 2002 10:35
Beiträge: 4234
Wohnort: Dortmund
Evil-Devil: Das Free wird nicht einfach irgendwo aufgerufen. Sondern kontrolliert dann, wenn das Interface nicht mehr verwendet wird. Bei normalen Klassen kann man solch einen Effekt auch erzeugen. Und zwar in dem man die Klasse frei gibt und sich dessen Pointer merkt und später darauf zugreift.

Conan: Du gehst mit deinen Objekten einen ganz anderen Ansatz als das was Delphi damit normal bezweckt hatte. So was sind ganz nützliche Hintergrundinfos. Wir können natürlich nur das berücksichtigen was wir wissen. Und wenn wir nur die Hälfte wissen, dann kann es passieren, dass dir die Antworten nicht viel nützen.

Die Interfaces so wie sie in Delphi implementiert sind bezwecken, dass man ausschließlich nur Interfaces benutzt. Speziell bei COM ist es so. Also selbst deine Basecomponent wäre dann auch ein Interface. Das könnte dann wiederrum weitere Interfaces unterstützen. Also von wegen. Darf angeklickt werden oder es darf Text eingeben werden etc. Dort ist es nicht vorgesehen, dass die implementierenden Klassen und die beschreibenden Schnittstellen gemischt benutzt werden. Von daher ist die verwendete Referenzzählung auch vollkommen okay. Das ist keine Garbage-Collection. Das sollte auch nie eine werden. Das ist nur eine Zählung wie sie auch bei String und bei DynArrays zum Einsatz kommt. Und die kann man bei Strings/DynArrays durch Umwege natürlich auch austricksten.

Es spricht aber natürlich überhaupt nichts dagegen, wenn man doppelten Code vermeiden möchte. Ganz im Gegenteil. Jede Redundanz ist eine potentielle Schwachstelle.

Zur TInterfaceList. Der Unterschied zu einer TList besteht nur darin, dass anstelle eines Pointers ein IInterface dort abgelegt wird. Und das ist das Basisinterface was alle Interfaces durch TInterfacedObject automatisch unterstützen. Du könntest an der Stelle durch die Liste gehen und würdest erfragen ob die abgelegten Interface das IPositionable unterstützen oder nicht. Wenn nicht, dann liefert QueryInterface einen Wert ungleich 0 zurück. Bei 0 würde das Objekt IPositionable unterstützen.

Wenn du das denn unbedingt möchtest, dann könntest du natürlich auch TInterfaceObject ersetzen. In wie fern das irgendwo Probleme machen könnte kann ich nichts sagen. Da es bisher noch nicht nötig war, dass ich so etwas machen musste. Bzw ist mein Schreib und Objektstil auch sehr streng. Entsprechend versuche ich solche Sachen auch zu vermeiden.

PS: In der VCL ist das was du machst mehrstufig Implementiert. TComponent > TControl > TGraphicControl / TWinControl. Wie man so was macht ist aber Geschmackssache.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Sep 18, 2009 10:28 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Das wichtigste, was man bei Interfaces nie vergessen sollte, man nimmt nie die Implementation mit. Nur die Deklaration. Mit Implementation wäre es die Mehrfachvererbung, die man von C++ kennt.

Ich würde daher auch eher den Ansatz von Traude vorschlagen. Einfach die VCL nachahmen. Das Prinzip ist schon gar nicht so schlecht. Ob die Events dann wirklich gewollt sind, kann man dann immer noch mit einem Boolean-Flag regeln (siehe ComponentStyle / ControlStyle).

Bei meiner GUI habe ich das ganz ähnlich gemacht. Ich habe eine Basisklasse, die alle Methoden zumindest protected implementiert (Grundfunktionalität, meistens aber gar nichts), und die werden dann von den Descendants überschrieben, wenns denn gebracht wird.

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy 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


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Sep 18, 2009 10:30 
Offline
DGL Member
Benutzeravatar

Registriert: Di Sep 03, 2002 15:08
Beiträge: 662
Wohnort: Hamburg
Programmiersprache: Java, C# (,PhP)
@free/interface: Ok, das bedeutet für mich als Delphi Laie das Interfaces anders gehandhabt sind als zb. in Java. Da kann ich keine Interfaces freigeben ^^"

_________________
(\__/)
(='.'=)
(")_(")


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Sep 18, 2009 11:33 
Offline
DGL Member
Benutzeravatar

Registriert: Di Nov 07, 2006 13:37
Beiträge: 83
Wohnort: Partenheim
@Traude: Du hast nicht zufällig ein Klassendiagramm o. ä. da, was euer Konzept verdeutlicht? Es interessiert mich sehr, aber ich kann es noch nicht ganz nachvollziehen.
Wenn ich das richtig verstehe, dann löst ihr bei z.B. OnKeyDown oder onMouseDown ein Event aus, so, wie die VCL es tut. Das ist ein Aspekt, der mir an der VCL nicht so sehr gefällt. Ich würde gerne versuchen, das über die Vererbung zu realisieren, wie SWING es tut.
Nicht, dass in SWING kein Ereignis-Delegations-Modell benutzt wird. Aber eben nicht so stark wie in der VCL.
Aber vielmehr interessiert mich gerade der Teil, wie genau ihr die 3 Komponenten (BaseComponent, WindowComponent, Observer) vernetzt.

Mein Fehler war, in den Delphi-Interfaces das zu sehen, was, wie Evil-Devil schon sagt, sie in JAVA sind.

Danke.
Conan

_________________
THE TRUTH IS NOT OUT THERE!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Sep 18, 2009 13:15 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Zitat:
Du hast nicht zufällig ein Klassendiagramm o. ä. da, was euer Konzept verdeutlicht?

Na hör mal, da ist doch eine schöne PDF-Beschreibung beim Download dabei: ttp://glpasgui.bplaced.net/
Diagramme gibt es auf Seite 3 und Seite 6.


Verbal beschrieben geht das so: In der Unit OSSupport.pas ist ein Record "TEventPipeline" definiert. Die Felder dieses Records bestehen nur aus Methodenzeigern.

In der GUI.Pas gibt es den TAdministrator, der in seiner Methode "InitEventPipeline" in diese Methodenzeiger seine eigenen Methoden "hineinsteckt".

Wenn Du jetzt in die OSSupportWin32.inc, Methode "InternEventReceive" hineinschaust, findest Du dort zum Beispiel in der großen Case-Anweisung bei "WM_KEYDOWN" den Aufruf von "OnKeyDown(AWindow, WParam, PreviousKey);"

Dieses OnKeyDown IST bereits die Methode des Administrators. Der Administrator hat zwei Aufgaben:

1. Er betreibt die Programmhauptschleife (so wie TApplication)
2. Er holt die Events vom Betriebssystem und gibt sie an das zuständige Fenster weiter.

Das Fenster selber weiß ja immer, welches das grade aktuelle Item ist und kann daher das Event gleich direkt an das richtige Item weitergeben.


Alles ist mit Callbackroutinen implementiert, dadurch geht das blitzschnell. Das war ein Tip von Lars Middendorf - Delphi ist in dieser Hinsicht schneller als Java. Die ganzen Callbackroutinen sind möglicherweise ein wenig verwirrend, aber glaub mir, wenn man sich da mal dran gewöhnt hat, ist man in Punkto Schnelligkeit kaum zu schlagen. Einen kurzen Check ist diese Lösung bestimmt wert.

Nochmal kurz: Betriebssystem => Administrator => Fenster => Item. Die Pfeile symbolisieren eine DIREKTE Verbindung.

Ich freu mich, dass das jemand mal anschaut, da stecken zwei Jahre Knochenarbeit drin. Ich habe in der Zwischenzeit schon etliche Verbesserungen gemacht, aber noch nicht hochgeladen (Testen ist nicht gerade motivationsfördernd): allgemeines Clipping und ein Delphi-konformes StringGrid sind die Highlights, die mir grade einfallen. :wink:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Sep 18, 2009 14:27 
Offline
DGL Member
Benutzeravatar

Registriert: Di Nov 07, 2006 13:37
Beiträge: 83
Wohnort: Partenheim
Vielen Dank, ich schau' gleich rein!!

_________________
THE TRUTH IS NOT OUT THERE!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Sep 18, 2009 17:58 
Offline
DGL Member
Benutzeravatar

Registriert: Di Nov 07, 2006 13:37
Beiträge: 83
Wohnort: Partenheim
Hi Traude!

Sehr starke GUI! Ich wusste gar nicht, dass ihr so viel da reingebaut habt :shock:

Zitat:
3.6 Overview of the GUI TREE structure
The operating system delivers events to the top of the GUI tree (the „Administrator“), which
distributes it to its windows, which again send it to their GUI items.
The Main Window is the owner of the Graphic Utility Manager and all windows (and items) have
access to its features.


Ich hab' auch schon in den Code geschaut und gesehen, dass sich unsere Ansätze "kaum" unterscheiden. Nur, dass ihr mein Problem löst, indem ihr alles in eine Datei schreibt und jedem Item Zugriff auf sein Window und jedem Window Zugriff auf sein MainWindow gebt.
Genau das will ich ja auch, nur eben gerne, ohne alles in eine Datei schreiben zu müssen. Zu oft habe ich mich schon mit dieser Variante zufriedengegeben.
Es resigniert mich, zu sehen, dass ich wohl schon so weit aus der Pascalwelt ausgestiegen bin, dass ich zwar ein Fan der Sprache, aber nicht der (Pflicht-)Konvention bin, alles, was in zirkulärer Abhängigkeit zueinander steht, in eine Datei zu schreiben. Das könnte mir in Zukunft (Zukunft?) Schwierigkeiten bereiten :lol:

Noch ein paar Fragen (wenn's dich nervt, sag Bescheid. Ich denke nur, du hast sie schneller beantwortet, als dass ich die Antworten im Code finde):
- wie macht ihr das mit dem focusedItem? Jedes Window hat bei euch ein focusedItem. Sind die denn alle, bis auf eins, nil? Oder ist es eine Art verkettete Liste bis zum letzten focusedItem? Ich habe mir gedacht, mein Observer bewahrt das focusedItem auf, sonst keiner, und z.B. das MouseDown gibt das getroffene Item zurück (an den Observer), auf das dann Dinge wie Tastatureingaben angewandt werden.
Euer focusedItem ist:
Code:
  1. item := MainWindow.focusedItem;
  2. While (item.focusedItem <> nil) do
  3.   item := item.focusedItem;

Sehe ich das richtig?
- Was genau tut "Space2d (Graphic Utility Manager)"? Warum kennt das MainWindow seine Windows einmal direkt und dann nochmal über Space2D? (hier beziehe ich mich auf das Diagramm zu Punkt 3.6)
- (nur Interesse) Wozu ist das ArmouredWindow? Das konnte mir die Doku leider nicht erklären.

Recht herzlichen Dank schonmal für die Mühe.
Conan

_________________
THE TRUTH IS NOT OUT THERE!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Fr Sep 18, 2009 22:15 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Zitat:
Ich hab' auch schon in den Code geschaut und gesehen, dass sich unsere Ansätze "kaum" unterscheiden. Nur, dass ihr mein Problem löst, indem ihr alles in eine Datei schreibt und jedem Item Zugriff auf sein Window und jedem Window Zugriff auf sein MainWindow gebt.
Genau das will ich ja auch, nur eben gerne, ohne alles in eine Datei schreiben zu müssen. Zu oft habe ich mich schon mit dieser Variante zufriedengegeben.
Nein, das täuscht. Man kann ein neues Item durchaus in eine andere Unit schreiben. Ich hatte lange Zeit das ganze Zeug getrennt in eine Unit GUI.pas mit: TGUIItem, TGUIWindow und TAdministrator, und eine zweite Unit Descendants.pas und dem ganzen Rest. Wenn ich ein neues Item mache, erzeuge ich das in einer getrennten Unit, denn zum Testen ist die GUI.Pas zu unhandlich.

Ich habe dann kurz vor der letzten Release (im Februar oder so) alles in eine Unit gepackt, aber das soll mehr eine Erleichterung für den Benutzer sein. Ich erinnere mich, dass es eine einzige Stelle gab, bei der vermutlich ein Problem auftaucht, wenn man die Descendants wieder aus der GUI.Pas herausnehmen möchte. Falls Du das mal versuchsweise tun willst, wird der Compiler sowieso schreien, also es könnte ein Problem mit der Sichtbarkeit von einer Prozedure/Property geben, aber nichts ernstes.

Zitat:
Es resigniert mich, zu sehen, dass ich wohl schon so weit aus der Pascalwelt ausgestiegen bin, dass ich zwar ein Fan der Sprache, aber nicht der (Pflicht-)Konvention bin, alles, was in zirkulärer Abhängigkeit zueinander steht, in eine Datei zu schreiben. Das könnte mir in Zukunft (Zukunft?) Schwierigkeiten bereiten Laughing
Da bist Du im Irrtum, das muss man nicht. Kommt auf den Code an. Es gibt ein paar Tricks. Aber bitte nicht heute, es ist sowieso schon so ein langer Beitrag.

Zitat:
wie macht ihr das mit dem focusedItem? Jedes Window hat bei euch ein focusedItem. Sind die denn alle, bis auf eins, nil?
Hm, das versteh ich nicht, wie Du das meinst. Die Windows sind echte Betriebssystem-Windows. Und jedes Betriebssystem-Window hat eben ein Item, das als letztes angeklickt wurde. Die Fenster sind ganz unabhängig voneinander, und daher haben diese FocusedItems gar nichts miteinander zu tun. (Also ich kann meinen Knopf nicht mit der Enter-Taste anklicken, nur mit der Maus). Ach so, Du lässt den Observer alles machen. Nein das ist bei mir anders. Der Administrator ist nur ein "Zureicher" und füttert die Fenster mit Events. Aber ansonsten hat er nichts zu reden (So wie ein Pascha mit Harem, wenns im Harem rundgeht, schmeissen sie ihn raus :wink:). Jedes (Betriebssystem-)Fenster übernimmt die Verantwortung für seine Items selbst. Die Fenster sind auch verantwortlich für das Zeichnen: jedes Fenster hat seinen eigenen Rendering Context. Das Item darf vom Fenster das Neuzeichnen verlangen, NICHT vom Administrator, denn der wüsste auch gar nicht, was zu tun ist.

Zitat:
Euer focusedItem ist:
Code:
item := MainWindow.focusedItem;
While (item.focusedItem <> nil) do
item := item.focusedItem;

Sehe ich das richtig?

Nein, nicht ganz. Wenn Du logisch denkst, kannst Du ganz leicht erraten, wo der Code dafür steht: im TGUIWindow.MouseBtnLDown, dort kommt nämlich der neue Mausklick herein. Du erinnerst Dich: ein Mausklick kommt aus der EventReceive-Prozedur aus dem Betriebssystem in die TAdministrator.MouseBtnLDown und diese liefert sie weiter an die TGUIWindow.MouseBtnLDown. Dort steht:
Code:
  1. Begin
  2.    OldFocusedItem:= FocusedItem;   // Altes FocusedItem sichern
  3.    fFocusedItem:= TREEHit(X,Y);    // Schauen, welches der Benutzer angeklickt hat (ein TREE-Rekursion)
  4.  
  5.    If (fFocusedItem <> NIL) Then Begin  // WENN er eins angeklickt hat:
  6.       If OldFocusedItem <> NIL          //    und wenn vorher schon eins angeklickt war
  7.          Then OldFocusedItem.Focused:= FALSE;   // dann altes FocusedItem benachrichtigen, dass es nicht mehr fokussiert ist
  8.       fFocusedItem.Focused:= TRUE;      //  Neues FocusedItem benachrichtigen, dass es focussiert ist
  9.       If(fFocusedItem <> Self)          //  Wenn das neue FocusedItem nicht das Window selbst ist
  10.          Then fFocusedItem.MouseBtnLDown(X,Y,AddKeys);  // dann das neue FocusedItem benachrichtigen, dass es angeklickt wurde
Also, ich hoffe, es ist gut verständlich.

Zitat:
Was genau tut "Space2d (Graphic Utility Manager)"?
Die GUI.pas selber enthält nur Pascal Code. Die Items dort sind so etwas wie "Innenarchitekten" aber mit dem Zeichnen selber geben sie sich nicht ab. Der Graphic Utility Manager stellt Schriften (TStdFont), Bilder(TStdImage) und 2DFormen(TStdShape2D) zur Verfügung und bewahrt sie in einer TObjectList auf. Auf Anforderung gibt er die Dinge heraus oder, wenn er sie nicht vorrätig hat, lädt er sie.

Zitat:
Warum kennt das MainWindow seine Windows einmal direkt und dann nochmal über Space2D? (hier beziehe ich mich auf das Diagramm zu Punkt 3.6)

Das Window kennt seine "Brüder" eigentlich gar nicht. Die gelben Linien in dem Diagramm sind bloss das Sinnbild dafür, dass der Adminstrator alle Fenster in einer TObjectlist hält. Es wäre aber möglich, etwas über die "Geschwister" herauszufinden, das gibt es eine ganze Menge einschlägige Properties im TGUIItem: "Protected parent/child/sibling properties (read only)"

Die rote Linie soll anzeigen, dass alle Fenster die Dienste des Space 2D in Anspruch nehmen können (nämlich Schriften,Bilder und Formen erhalten), aber nur das Hauptfenster berechtigt ist, einen Space2D zu erzeugen. Der Space2D sollte eigentlich ein Singleton sein, ist er aber in der aktuellen Version nicht. Der Space2D ist so etwas wie eine Canvas.

Zitat:
Wozu ist das ArmouredWindow?

Ich hatte mir vorgenommen, keine nativen Betriebssystem-Fenster anzuzeigen (also keinen blauen XP-Balken). Das normale Fenster (= TGUIWindow) ist nur ein Viereck auf dem Desktop. TArmouredWindow ist ein "Fake"-Betriebssystem-Fenster, bei dem der Balken mit OpenGL gezeichnet ist. Die Fenster, die Du auf der Website siehst, sind TArmouredWindows. Hab mir damit ganz schön Schwierigkeiten eingehandelt. Eigentlich ein Anachronismus, aber was soll's.

Und zuletzt zwei kurze Hinweise:

1.Ich habe diesen Code allein geschrieben. Viele haben mir geholfen, aber nur mit Rat, nicht mit Tat. Du kannst das "Ihr" getrost durch "Du" ersetzen.
2.Ich weiß nicht, ob Du ein Linux-Mensch bist oder SDL benutzt:
***Die glPasgui stellt einen RC pro Fenster zur Verfügung, also nur für OpenGL bis Version 2.1, für das reine Zeichnen mit OpenGL braucht sie daher kein SDL. Sie hat aber kein Netzwerk oder ähnliche Zusatzkomponenten dabei.
***Das Programm sollte sich ohne weiteren Änderungen auch auf Linux mit Lazarus kompilieren lassen, OSSupportX11.Inc machts möglich.

Puh, das war jetzt eine lange Litanei, und ich hab trotzdem das Gefühl nur einen Bruchteil gesagt zu haben. :(
Traude


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Sep 19, 2009 13:34 
Offline
DGL Member
Benutzeravatar

Registriert: Di Nov 07, 2006 13:37
Beiträge: 83
Wohnort: Partenheim
Das "ihr" ist eine Ehrenbezeichnung 8)


Zitat:
Zitat:
Ich hab' auch schon in den Code geschaut und gesehen, dass sich unsere Ansätze "kaum" unterscheiden. Nur, dass ihr mein Problem löst, indem ihr alles in eine Datei schreibt und jedem Item Zugriff auf sein Window und jedem Window Zugriff auf sein MainWindow gebt.
Genau das will ich ja auch, nur eben gerne, ohne alles in eine Datei schreiben zu müssen. Zu oft habe ich mich schon mit dieser Variante zufriedengegeben.
Nein, das täuscht. Man kann ein neues Item durchaus in eine andere Unit schreiben. Ich hatte lange Zeit das ganze Zeug getrennt in eine Unit GUI.pas mit: TGUIItem, TGUIWindow und TAdministrator, und eine zweite Unit Descendants.pas und dem ganzen Rest.


Ich meinte, du kannst TGUIItem und TGUIWindow nicht in getrennte Units schreiben. Oder gibt's dafür einen Trick (außer Interfaces :? )
Ansonsten ist das eine schöne Lösung, die ich, demütigst, eure Hoheit, übernehmen werde.
Danke für deine Hilfe. Dann werden BaseComponent und WindowComponent für's erste mal in einer Datei stehen, bis mir was besseres einfällt. Das scheint mir die eleganteste Lösung.

Conan

P.S.
Zitat:
Da bist Du im Irrtum, das muss man nicht. Kommt auf den Code an. Es gibt ein paar Tricks. Aber bitte nicht heute, es ist sowieso schon so ein langer Beitrag.

Neuer Tag, neuer Beitrag. Was sind das für Tricks?

_________________
THE TRUTH IS NOT OUT THERE!


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Sa Sep 19, 2009 22:28 
Offline
DGL Member
Benutzeravatar

Registriert: Di Okt 03, 2006 14:07
Beiträge: 1277
Wohnort: Wien
Zitat:
Ich meinte, du kannst TGUIItem und TGUIWindow nicht in getrennte Units schreiben.
Ja, Du hast recht. Das Item muss sein Window kennen, denn er muss mit dem Window kommunizieren können, deswegen auch die Forward-Deklaration "TGUIWindow=Class" und es gibt auch noch ein paar weitere Forward-Deklarationen. Und dann bin ich gezwungen, das TGUIWindow im selben Block zu definieren.

Die Basis-Items habe ich auch schon deswegen zusammen in eine Unit gesteckt, um dem User keinen Zugriff auf bestimmte Felder zu geben, denn da kann nur Unsinn rauskommen, wenn da jemand herumfummelt. Und ich fand damals, dass es kein Nachteil ist, die Basis-Items zusammen in einer Unit zu haben. Dann habe ich das ArmouredWindow gemacht und das braucht diese Symbol-Buttons... Tja und dann müssen ein paar Items mehr in diese Unit: Das TScrollingItem, der TButton, usw. das passiert dann einfach im Laufe der Entwicklung. Du hast jetzt die Chance, meine Fehler zu vermeiden.

Mögliche Lösungswege, die ich kenne: siehe unten.

Zitat:
Das "ihr" ist eine Ehrenbezeichnung
Wow. 8)

Zitat:
Neuer Tag, neuer Beitrag. Was sind das für Tricks?

Erstens, die ganz triviale Lösung: die Dinge, die ein Objekt vom anderen braucht, werden public deklariert. Dann können zwei verschiedene TGUIItems miteinander kommunizieren, und es macht nichts aus, wenn das eine ein TGUIItem ist und das andere ein von TGUIItem abgeleitetes TGUIWindow. Aber ich nehme an, das hast Du schon gewusst. Und außerdem: diese beiden können nur auf TGUIItem-Level kommunizieren.


Zweitens, eine Lösung, die ich mir mal für eine Datenbank-Anwendung ausgedacht habe:

Ein immer wiederkehrendes Problem ist, dass zwei Objekte einander kennen sollten, aber es kann nur das nachfolgende Objekt das vorhergehende kennen. MatReno und Dir sollte das Problem gut bekannt vorkommen: ich habe ein Hauptspeicherobjekt, dessen Daten irgendwie geladen werden müssen. Ich möchte den Loader aber gerne als eigenes Objekt machen, damit ich verschiedene Loader bequem implementieren kann.

Meine Benutzerschnittstelle soll so aussehen:

MyObject3D:= TObject3D.Create;
MyObject3D.Load(Bluemchen.obj);

Das Problem ist, dass das Object3D den Obj-Loader kennen sollte (es muss diesen Loader erzeugen können), aber der Obj-Loader sollte auch das Object3D kennen (er muss wissen, wie er dem Objekt die Daten überreichen soll). Nun könnte man natürlich hier ein Interface nehmen, das ist ja sogar der klassische Fall für ein Interface. Aber ich mag keine Interfaces, weil sie einem das Objekt unterm A*** naja Du weißt schon wegziehen. Ich arbeite lieber mit ganz normalen Objekten.

Und das geht so:

Schnittstelle, erster Teil: Man definiere ein TCustomObject3D, das nur die Features hat, die der Loader kennen soll. Das sind hauptsächlich ganz gewöhnliche Properties und deren Getter und Setter.

Schnittstelle, zweiter Teil: Dann definiert man ein TCustomLoader, der nichts anderes kann, als die Properties des TCustomObject3D mit Daten zu versorgen. Voilà, die Schnittstelle ist definiert und außerdem in zwei Teile zerhackt. Beide Objekte kann man in verschiedene Units stecken.

Anschließend kann man verschiedene Abkömmlinge von TCustomLoader (in anderen Units) definieren, z.B.: TOBJLoader = Class(TCustomLoader); Alle diese Loader sind jetzt mit einer geerbten bequemen Zugriffsmöglichkeit zum TCustomObject3D ausgestattet, die sie ganz nach Belieben verwenden können.

NACHHER formuliert man das TObject3D = Class(TCustomObject3D) (kann auch in einer extra Unit sein) und definiert es so, wie man es eben braucht.

Dieses Objekt erhält einen als Private deklarierten Loader: fLoader:= TCustomLoader;

Dem TObject3D müssen alle Loader bekannt sein. Denn dann kann ich schreiben:

MyObject3D.Load(Bluemchen.obj); oder
MyObject3D.Load(Bluemchen.dae); oder was auch immer

und das Objekt, das alle verfügbaren Loader kennt, sucht sich selber aufgrund der File-Extension den richtigen Loader aus und verwendet ihn:
Code:
  1. If FileExists('Bluemchen.obj')
  2.  
  3. Then Begin
  4.  
  5.    LoaderType:= GetLoaderType(ExtractFileExtension('Bluemchen.obj'));
  6.  
  7.    Case LoaderType Of
  8.  
  9.       ltOBJ: fLoader:= TObjLoader.Create;
  10.       ltDAE: fLoader:= TColladaLoader.Create;
  11.       ......
  12.       ......
  13.    End;
  14.  
  15.    Try
  16.       fLoader.Load('Bluemchen.obj');
  17.    Finally
  18.       fLoader.Free;
  19.    End;
  20. End;

Das Object3D hat beim Loading gar nichts zu tun. Es muss nur warten, bis der Loader fertig ist: Die Art und Weise, wie geladen wird, bestimmt der Loader, denn er ist ja der Spezialist dafür.

Was hab ich davon? Meine Objekte bleiben klein, leicht überschaubar und leicht erweiterbar und haben trotzdem eine Funktionalität, die, wenn man es mit den herkömmlichen Pascal-Mitteln versucht, riesige unhandliche Objekte brauchen würden. TObject3D und alle seine Loader agieren so, als ob sie ein einziges Objekt wären - sie sind es aber nicht. :wink:

Zusätzlich kann man das mit den ganz gewöhnlichen Pascal-Mitteln machen und es ist total simpler Code.

Ich nenne die beschriebene Technik "Verschränkte Objekte", aber Flash hat bestimmt wieder einen IT-Fachausdruck parat.

Wenn man die verschränkten Teile (also TCustomObject3D und TCustomLoader) zusammen in eine Unit tut - was möglich, aber nicht zwingend ist -, hat man auch noch die Option, dass die beiden "Private" Daten austauschen können, auf die der Nutzer keinen Zugriff hat. Its a feature, not a bug!

Oder man nimmt *örps* Interfaces. Vermutlich kann man es auch noch auf andere Arten machen.

Viele Grüße,
Traude

PS: Ich bin gar nicht so hochnäsig, wie ihr offenbar alle annehmt. Nur ein bissel störrisch: ich mag keinen Internet-Slang verwenden. Ansonsten bin ich ganz harmlos. Ist mir auch schleierhaft, warum die Wärter abends immer meine Zelle von außen absperren .... :twisted:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Sep 20, 2009 12:17 
Offline
DGL Member
Benutzeravatar

Registriert: Di Nov 07, 2006 13:37
Beiträge: 83
Wohnort: Partenheim
Hi Traude!

Zu meiner Schande muss ich gestehen, dass ich das, was du als zweiten Lösungsweg vorgeschlagen hast, nie getestet habe, da ich dachte, Delphi verbietet es aus Gründen "Zirkulärer Referenz zweiter Stufe" oder sowas. :oops:
Aber ich habe es gerade eben ausprobiert und es funktioniert einwandfrei. Wenn das 3DObject den CustomLoader kennt, kann der Loader sogar direkt das 3DObject kennen, ohne den Umweg über das Custom3DObject gehen zu müssen. Das ersetzt fast die Interfaces, bis auf die Mehrfachvererbung.
Das bringt die Modularisierung meines Delphicodes wieder einen Schritt voran. Ich danke dir für diesen Tipp.

Zitat:
MatReno und Dir sollte das Problem gut bekannt vorkommen

Oh ja, damit haben wir uns schon so häufig herumgeschlagen. Aber damals waren wir noch klein und dumm, muss ich rückblickend zugeben (und das nimmt er mir hoffentlich nicht übel :wink: )

Grüße
Conan

_________________
THE TRUTH IS NOT OUT THERE!


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 31 Beiträge ]  Gehe zu Seite Vorherige  1, 2, 3  Nächste
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 4 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.010s | 15 Queries | GZIP : On ]