Hallo Ttraude!
zu Punkt 1 sehe ich folgendes Problem:
Code:
TFoo=Class;
TBar=Class(TObject)
private
oFoo: TFoo;
protected
Procedure SetFoo(Value: TFoo);
published
Property Foo: TFoo read oFoo write setFoo;
End;
TFoo=Class(TObject)
private
oBar: TBar;
published
Property Bar: TBar Read oBar Write oBar;
End;
Implementation
Procedure TBar.SetFoo(Value: TFoo);
Begin
oFoo:=Value;
oFoo.Bar:=Self;
End;
Hier hast Du eine klassische Ringverbindung, de durchaus vorkommen kann (z.B.: Parent/Cleint Bezug). Dieser Ring sorgt für eine unendlich große gesicherte Datei.
zu 2. Ist OK. Philosophiefrage. Allerdings birgt es das Risiko, dass man oben genannten Ring nicht auflösen kann, dadurch, dass man eine der beiden Properties aud Public setzt, weil wenn man die von TFoo public macht, geht die Beziehung flöten. (Man muss Hier also teuflisch gut aufpassen)
zu 3. Der Parser weiss nicht, dass vor dem Schreiben die Reset-Methode gerufen werden muss, und so werden u.U. nicht alle Elemente der Liste gespeichert (wenn z.B.: der Zähler auf dem 3. Element steht).
zu Deinem Einwand mit nicht jedes Objekt speichern: Du hast Recht, man muss erst einen Nachfolger schreiben, der das Interface hat. Aber dieser Nachfolger kann einen beliebigen Vorgänger haben.
zu Deinem Problem mit dem Destruktor: Du kannst (theoretisch) mit GetProcAddress den Destruktor ziehen, aber nicht ersetzen, wirst also trotzdem nicht mitbekommen, ob es zerstört ist. Dieses Problem habe ich umgangen, indem ich als Konvention eingeführt habe, dass der Delegat ein TComponent als Owner hat. Aber wie gesagt: es sind zwei gleichwertige aber verschiedene Ansätze und da musst Du eben damit leben, dass das Objekt schon weg sein kann und das ganze mit try..except-Blöcken sichern.
_________________ Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.
Eine 2. Sache ist TDGL_DataProvider, TRTTI_Handler und TRTTI.
Wieso für die gleiche funktionalität unterschiedliche Klassen ?
Wieso nicht TRTTI und TDGL_DataProvider=class(TRTTI); und dann nur noch TDGL_DataProvider nutzten ?
So muss ich für Datei ein und ausgabe den DataProvider nutzen und für häufigeren zugriff TRTTI_Handler.
Ich hab gestern mal den aktuellen Code unter Vista probiert und funktioniert dort genauso gut wie unter WinXP.
Zum Array und Record kann ich folgendes sagen.
Ich hab den array ganz einfach über eine property funktion gelöst also property getitem:function (index:integer):pointer read fgetitem; Records werden von FreePascal aktuelle nich unterstützt aber man kann ja auch die variablen vom record in eine Klasse packen.
_________________ "Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren" Benjamin Franklin
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Tak schrieb:
Zitat:
Ein Problem ist das registrieren von Klassen. Classes.pas bietet dafür schon funktionen an, unzwar GetClass und FindClass.
Danke für den Hinweis. Werde ich berücksichtigen.
Zitat:
Alle Klassen die vom Typ TPersistant sind also mit RTTI Daten ausgestattet werden sollen werden automatisch registriert und können so abgerufen werden. Ich bin auch dafür TDGL_Widget von TPersistantClass ab zu leiten, damit kann man sich auch das {$M+} {$M-} bei folgenden Klassen sparen.
Werde ich ebenfalls berücksichtigen.
Zitat:
Eine 2. Sache ist TDGL_DataProvider, TRTTI_Handler und TRTTI. Wieso für die gleiche funktionalität unterschiedliche Klassen ?
TRTTI war das ursprüngliche Konzept, das haben sie mir zerschossen. Der TRTTI_Handler ist das neue Konzept ANSTATT des vorherigen TRTTI. Wenn wir das TDGL_Widget von TPersistent ableiten, passt es dann wieder. Ich habe bereits eine neue funktionierende Version. Aber ich muss sie noch auf Fehler abklopfen.
Der neue TDataProvider hat einen (privaten) TRTTI_Handler mit und steckt an diesen das Objekt, das er laden und speichern will, an, kann so die Daten und auslesen oder eingeben.
Traude
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Sidorion schrieb:
Zitat:
Hier hast Du eine klassische Ringverbindung, de durchaus vorkommen kann (z.B.: Parent/Cleint Bezug). Dieser Ring sorgt für eine unendlich große gesicherte Datei.
Ha, danke für den Hinweis. Ich habe das in diesem Forum schon öfters gesehen, solche Ringverbindungen. Das ist eine harte Nuß. Muss ich noch klären.
Zitat:
zu 2. Ist OK. Philosophiefrage. Allerdings birgt es das Risiko, dass man oben genannten Ring nicht auflösen kann, dadurch, dass man eine der beiden Properties aud Public setzt, weil wenn man die von TFoo public macht, geht die Beziehung flöten. (Man muss Hier also teuflisch gut aufpassen)
Ja.
Zitat:
zu 3. Der Parser weiss nicht, dass vor dem Schreiben die Reset-Methode gerufen werden muss, und so werden u.U. nicht alle Elemente der Liste gespeichert (wenn z.B.: der Zähler auf dem 3. Element steht).
Ich möchte das Objekt (das TDGL_Widget) selbst den DataProvider dirigieren lassen. Das Objekt kann "OnSave" dafür sorgen, dass immer alle gespeichert werden, indem es in dieser Prozedur ein Reset aufruft.
Zitat:
Aber wie gesagt: es sind zwei gleichwertige aber verschiedene Ansätze und da musst Du eben damit leben, dass das Objekt schon weg sein kann und das ganze mit try..except-Blöcken sichern.
Du kannst Dir beim Schreiben alle Pointer merken, die Du angefasst hast, und beim Rekursieren schaun, ob dieser Pointer schon geschrieben wurde. Beim Lesen sind dann einfach keine Daten für diese Property im Stream.
Das Problem mit den Records konnte ich mit meinem Ansatz durch die OwnerStreams lösen, aber man könnte auch (wie TAK glaub ich schrieb) die Records nach Klassen portieren. Dies hätte aber imho den Nachteil, dass Klassen nunmal langsamer verwaltet werden als Records (ein .Create ist halt langsamer als ein new()) und dem Nutzer die Möglichkeit der Verwendung von Records verwehrt bleibt.
_________________ Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Sidorion schrieb:
Zitat:
Du kannst Dir beim Schreiben alle Pointer merken, die Du angefasst hast, und beim Rekursieren schaun, ob dieser Pointer schon geschrieben wurde. Beim Lesen sind dann einfach keine Daten für diese Property im Stream.
Ja, aber damit kann ich ihn nicht stoppen, oder? In Deinem obigen Beispiel würde die Speichermethode endlos hin und her springen. Aua! sieht ja fast wie ein Virus aus. Woran würde ein Mensch diese Endlosschleife erkennen? Ich glaube: AM WEG.
Wenn man in dem Beispiel oben sich die Pointer in eine Liste schreibt, fangen sie sich an, zu wiederholen. Das müsste man doch erkennen können. Oder bin ich am Holzweg? Schaut nach Mustererkennung aus.
Man merkt sich, wie schon geschrieben, alle Objekte in einer Liste. Wenn ein Zeiger das erste mal geschrieben wird, schreibt man das ganze Objekt mit allen Eigenschaften. Bei allen weiteren malen schreibt man nur noch den Index in der Liste.
Das Einlesen geschieht ja in der gleichen Reihenfolge. Daher braucht man dann nur zu schauen ob man das Objekt schon gelesen hat. Wenn nicht, dann folgen auf jeden Fall die Eigenschaften, ansonsten nimmt man einfach den Zeiger aus der Liste.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Ich hatte mich oben etwas missverständlich ausgedrückt. Ich meinte eigentlich das Problem, das Sidorion als erstes angesprochen hat:
Zitat:
Hier hast Du eine klassische Ringverbindung, de durchaus vorkommen kann (z.B.: Parent/Client Bezug). Dieser Ring sorgt für eine unendlich große gesicherte Datei.
Er spricht hier davon, dass meine Speichermethode bei einer Ringverbindung in eine Endlosschleife degeneriert, und ich habe sinniert, wie ich das abfangen kann: wenn ich mir alle (auch die wiederholten) Zeiger speichere, müsste bei einer Endlosschleife ein sich wiederholendes Muster der Zeiger zu erkennen sein.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo,
Ich habe etwas länger gebraucht, letzte Woche war es etwas dicht. Ich habe einen Teil der besprochenen Änderungen des DataProviders und der RTTI-Schnittstelle implementiert, die noch nicht implementierten sind in die ToDo-Liste geschrieben, die sich im Kopfteil der jeweiligen Unit befindet (wo auch eine Problem-Liste steht). Ich möchte diese erst implementieren, wenn ich sie auch testen kann. Es sind beim RTTI_Handler zwei Dinge dazugekommen: "StrValByName", "StrValByIndex", die Werte als String ausgeben bzw. einlesen.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo an Alle.
Ich habe mal wieder ein Problem. Diesmal versuche ich meine Anwendung in eine leicht verständliche Form zu bringen und bin gerade beim Windows-Event-Dispatching:
Code:
Function EventReceiver(AWindow, AMessage,
WParam,LParam:Integer):Integer;
Type
TWordRec =RecordLow,High:Word;End;
Begin
With EventPipeline DoCase AMessage Of
WM_DESTROY:Begin
PostQuitMessage(0);// Sends WM_QUIT to the message queue
Beim Schicken der Events nehme ich WM_QUIT und WM_PAINT heraus.
WM_QUIT muss man nicht schicken. Aber WM_PAINT ist fatal, weil
Auszug aus dem Windows SDK, Stichwort "PeekMessage":
Zitat:
The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. However, if a WM_PAINT message has a null update region, PeekMessage does remove it from the queue.
Wenn ich WM_PAINT behandle, kriege ich nie ein OnIdle, weil IMMER ein WM_PAINT in der Schleife steht. Wenn ich meine Events so abhole wie oben, habe ich ein funktionierendes OnIdle und um das OnPaint muss ich mich offenbar selber kümmern. Oder hab ich was übersehen?
NACHTRAG: Ich habe in der Tat was übersehen:
Zitat:
If an application processes a WM_PAINT message but does not call BeginPaint or otherwise clear the update region, the application continues to receive WM_PAINT messages as long as the region is not empty. In all cases, an application must clear the update region before returning from the WM_PAINT message.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Kleiner Zwischenbericht:
Ich schlage mich gerade mit FreeType2 herum, weil ich die wgl-Schrift nicht will. Zumindest kann ich ihm schon Buchstaben entlocken.
Traude
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Das ist für meine eigene Testanwendung. Ich darf ja wegen des Multi-Window-Konzepts das SDL nicht verwenden. Und dann dachte ich mir, könnte ich gleich auf Freetype zurückgreifen. Vielleicht interessiert es jemanden.
Registriert: Sa Jan 01, 2005 17:11 Beiträge: 2068
Programmiersprache: C++
Schon, vorallem das SDL_TTF nicht alle Möglichkeiten von TTF wie Buchstabenabstand in Abhängigkeit des nachfolgenden Buchstaben beherscht.
Denoch wäre ich aber dafür, dass die Ergebnisse bitte in ein extra Topic kommen.
Danke
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Zwischenbericht:
----------------------
Ich habe in der Zwischenzeit eine Testanwendung gebastelt. Keiner kann behaupten, dass ich ungeduldig wäre. Ich hab sowas zunächst mal fürs TinyGUI gemacht, dann einen Vorschlag für Tak, der ihm nicht gefallen hat, und jetzt zum dritten Mal (ein viertes Mal mache ich es jedenfalls nicht mehr). Ich habe wirklich versucht, nach Euren Style-Vorgaben zu arbeiten, aber dafür brauche ich circa viermal so lange wie gewöhnlich. Daher habe ich mich entschlossen, es jetzt mal nach meiner Methode zu erstellen, wenns Euch gefällt schreibe ich es für Euch um (auch die Benennungen etc.).
Folgendes kann diese Testanwendung jetzt:
Sie zeichnet zwei Fenster, das linke zeichnet OnPaint, das rechte OnIdle
Programm beenden: nur mit Knopf "Close" des linken Fensters (ALT+F4 ist deaktiviert, siehe Unit OSSupport)
Linkes Fenster: anklickbare Knöpfe und ein Panel
Rechtes Fenster: mit den Tasten "Insert" und "Delete" kann das Panel samt Knopf (d.h. die ganze GUI des Fensters) ein- und ausgeblendet werden
Elemente können grundsätzlich "hovern"
Die quergestreiften Panels sind durchsichtig, verschiebbar und skalierbar, das ist nur zu Demozwecken. Das linke Fenster kann minimieren, maximieren, auf Normalgröße stellen und (die Anwendung) schließen, alles per Knopf. Der Knopf des rechten Fensters bewirkt nichts.
Wenn ihr meint, dass das OnIdle Fenster zu lahm ist, müsst Ihr das Sleep(40) in der Hauptschleife auskommentieren (Unit Main.dpr, ganz unten), dann gehts ein bissl schneller; ich hab die FPS dazugeschrieben - nur der Eintrag im "OnIdle"-Fenster ist der richtige.
Sonstiges:
----------------------
Übersetzbar mit Delphi7 und Free Pascal (im Delphi-Modus)
Zugrundegelegte API: bisher nur Windows
Die Fenster besorgen sich entweder den Rendering Context selbst oder müssen ihn sofort nach dem Create erhalten
keine Begrenzung der Anzahl der erzeugbaren Fenster
Noch keine ernstzunehmenden Widgets
Der DataProvider ist zwar bereits vorbereitet, aber noch nicht ins Programm eingehängt und speichert auch noch nicht das richtige Format
Exceptions sind noch nicht drin (die Vorbereitungen haben bisher einfach zu lange gedauert).
Themes hab ich mir ebenfalls noch nicht überlegt, aber das wird glaub ich jetzt keine Schwierigkeiten mehr machen.
Diese Anwendung ist nicht gänzlich gemäß den Vorgaben (ich habe z.B. Units statt der Include-Files), kann aber leicht Vorgaben-konform umgestaltet werden.
Last not Least: bitte entschuldigt die hässlichen Farben. Das war jetzt nicht mein vordringlichstes Problem.
Kurzbeschreibung:
-----------------------
MAIN.DPR ist das Hauptprogramm
ADMINISTRATOR.PAS beinhaltet einen Kümmerer (er kümmert sich um alles , auch ums Eventhandling). Ich habe ihn zwar aus dem TGUIItem abgeleitet, aber den kann jeder ableiten und gestalten, wie er will. Die Instanz dazu wird im Hauptprogramm erzeugt.
GRAPHICSUPPORT.PAS beinhaltet einen GraphikManager (mit Farben,Texturen,Schrifen und Zeichenprozeduren) und greift auf OpenGl zu (pro Fenster gibts einen GraphicManager und einen Rendering Context).
GUI.PAS enthält den eigentlichen Code, um den es geht
GUIDESCENDANTS.PAS enthält die DemoWidgets: das Panel und den Button
IMAGELOADER.PAS ist ein kleiner verhutzelter BMP-Loader, der noch erweitert werden soll
OSSUPPORT.PAS enthält den Code fürs Operating System - also Windows
RENDER3D.PAS beinhaltet die Zeichenprozedur für das bunte Zahlenbrett und ein paar Dinge, die ich beim Testen gebraucht habe
FAZIT: Ich bin jetzt wirklich (ich glaubs nicht!) an dem Punkt angelangt, wo ich mit den Widgets anfangen könnte.
Ich habe die Daten vorsichtshalber in drei Teile aufgeteilt. Die beiden DLLs gehören zur FreeTypeFont
ACHTUNG! Die dglOpenGl.pas ist auch nötig, ist aber bei diesen Daten nicht dabei. Noch zu beachten für FPC: nicht vergessen den Delphi-Modus einstellen und das aktuelle Verzeichnis auf das Anwendungsverzeichnis umzustellen.
Traude
NACHTRAG: Hab noch vergessen: die Panels lassen sich mit dem Mausrad zoomen.
NACHTRAG Nr.2: Hab natürlich noch etwas vergessen: die Fenster lassen sich auch verschieben und skalieren - einfach mit der Maus - auch wenn sie keinen Balken haben.
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.