Wie kann man Objekte dynamisch erstellen? (Einige OOP-Sachen) - Seite 5

 
Doerk Hilger:

2. Framework from scratch.

Similar here. When I started to go a bit deeper into the standard libraries I found many things, which I did not like. Not only the bad performance of those, but also lack of flexibility and also because of an incomplete architecture. I am missing for example a global CMouse class/object as well as a class between CWnd and CObject, because CWnd objects are childs of the chart as well as lines are, and there is no connection to such and no final implementation of any such objects at all like I described it above. And, there is no master object, which holds all such chart objects which makes it possible to show/hide all of them with one command, destroy them, whatever. CCanvas, same thing, a nice class but where is the implementation with CWnd which allows me to create interactive objects based on bitmaps that inherit from CWnd? And so on. 




Was ist die Rolle einer globalen CMouse? Dient sie dem Endbenutzer nur als eigenständige Klasse, um einfachen Zugang zur Mausverwaltung zu erhalten? Wie hängt sie mit dem Framework zusammen?
Was die Klasse zwischen CWnd und CObject angeht, so kann ich Ihrer Erklärung nicht folgen, warum Sie sie für notwendig erachten. CWnd-Objekte sind Kinder des Diagramms, ebenso wie Linien - ich verstehe das Problem nicht, und warum gibt es keine Verbindung?
Sie sagen auch, dass es keine endgültige Implementierung solcher Objekte gibt, wie Sie es oben beschrieben haben? (Wo haben Sie das beschrieben?)

 

Die Möglichkeit eines globalen Mausobjektes ist, zumindest in meiner GUI, alle Informationen über die Maus (Position, Druckposition, Preis der Position etc.) zu speichern, die für jede Klasse, die mit solchen Informationen arbeitet, zugänglich sind. Außerdem enthält das Mausobjekt Informationen über die ausschließliche Verwendung der Maus, z.B. beim Ziehen. Das spart einfach viel CPU-Zeit, wenn etwas gezogen wird oder angeklickt werden soll etc.

Und nicht zuletzt: Nichts aus der Standardbibliothek funktioniert im Strategietester, wenn es in EAs verwendet wird, weil es keine Mausereignisse gibt. Und wenn Sie eine Mausunterstützung im Strategietester implementieren wollen, werden Sie für eine solche Mausklasse auch dankbar sein, denn der Klasse ist es egal, woher die Informationen über Mausbewegungen kommen, aber die Objekte, die die Informationen benötigen, wissen trotzdem, wo sie suchen müssen.

---

Es ist nicht nur die Klasse zwischen CWnd und CObject, die mir fehlt, es ist eigentlich mehr das fehlende Master-Objekt/Container, das sowohl pixelbasierte Objekte als auch zeit-/preisbasierte Objekte enthält. Wie Sie schon sagten, sind sie alle Objekte des Diagramms, also sollte der logische Master ein Objekt sein, das das Diagramm repräsentiert und das alle Objekte enthält. Und um das zu realisieren, muss es eine Klasse zwischen CWnd und CObject geben.

Der Hintergrund für diese Idee ist nicht nur die Logik, sondern auch eine Frage der Performance. In meinem Fall erkennt das Master-Objekt, wenn sich das Diagramm in irgendeiner Weise ändert, es durchläuft eine Schleife über alle enthaltenen Objekte, die sowohl Container von Linien, Container von CWnd als auch einzelne Objekte von jedem dieser Typen sein können, und "informiert" jedes Objekt, das davon informiert werden möchte. Das heißt, es gibt nur eine einzige Schleife an genau einer Stelle im Code, und durch die Verwendung von Containern und Subcontainern ist das extrem effizient.

Ich verwende diesen Master auch, um alle Objekte auf einmal einzufrieren und mit nur einer Zeile Code jede physische Aktualisierung zu verhindern. Der Unterschied in der Leistung ist drastisch. Beispiel: Wenn ich alle visuellen Objekte erstelle, die ich für meinen EA benötige, und in manchen Fällen sind das mehr als 1000, friere ich dieses Master-Objekt im Voraus ein, erstelle die anderen Objekte und "taue" es danach auf, was zu einer einzigen physischen Aktualisierung des Charts führt. Ohne Einfrieren kann dieser Prozess eine ganze Minute dauern. Mit Einfrieren dauert er weniger als 2 Sekunden.

Bevor ich anfing, die GUI selbst zu erstellen, habe ich es mit den Standard-Libs versucht. Später habe ich versucht, zumindest einige Teile beizubehalten. Aber das Problem war, dass es einfach unmöglich war, das zu realisieren, was mir vorschwebte, wegen einer unvollständigen Implementierung und einer Architektur, die irgendwie ... LetsMakeSomethingThatWorksSomehowForWeDontKnow. Die visuelle Leistung wird mit einer klaren Hierarchie erreicht, aber die Standard-Bibliotheken sind irgendwie anarchistisch.

Jedenfalls bin ich nicht die erste Person, die das erkannt hat. Und wie Alain schon sagte, bin ich mir nicht sicher, ob das wirklich hilft, weil es zu theoretisch ist. Ich kann nur über meine Erfahrungen mit all diesen Dingen sprechen, die nicht nur auf MQL basieren, aber meine Meinung ist trotzdem nur meine Meinung und natürlich kein Gesetz.

 
Erstens bin ich nicht der Meinung, dass er zu theoretisch ist. Ich denke, es ist sehr aufschlussreich. Ich kann zustimmen, dass es für Leute, die nicht am Aufbau von Frameworks interessiert sind und sie nur zum Aufbau einer Benutzeroberfläche verwenden müssen, theoretisch ist.

Aber für den zweiten Typus ist die Denkweise und die Überlegungen, die hier diskutiert werden, sehr wertvoll und auch sehr praktisch. Natürlich wäre ein Artikel besser, aber trotzdem.
Ich glaube nicht, dass die Leute Frameworks bauen werden, nachdem sie nur diesen Thread gelesen haben, aber dennoch enthält er gute Informationen und Einsichten, die selbst den Leuten zu fehlen scheinen, die bereits öffentliche MQL-Frameworks gebaut haben.

Also, für die Maus und den Tester, wenn ich Sie richtig verstanden habe, verwenden Sie ::OnTester(), um Ihre Maus anstelle einer Benutzereingabe aufzurufen, wenn ich Ihnen folgen kann.

Nochmals vielen Dank, Doerk.
 
Doerk Hilger:

Die Möglichkeit eines globalen Mausobjektes ist, zumindest in meiner GUI, alle Informationen über die Maus (Position, Druckposition, Preis der Position etc.) zu speichern, die für jede Klasse, die mit solchen Informationen arbeitet, zugänglich sind. Außerdem enthält das Mausobjekt Informationen über die ausschließliche Verwendung der Maus, z.B. beim Ziehen. Das spart einfach viel CPU-Zeit, wenn etwas gezogen wird oder angeklickt werden soll etc.

Und nicht zuletzt: Nichts aus der Standardbibliothek funktioniert im Strategietester, wenn es in EAs verwendet wird, weil es keine Mausereignisse gibt. Und wenn Sie eine Mausunterstützung im Strategietester implementieren wollen, werden Sie für eine solche Mausklasse auch dankbar sein, denn der Klasse ist es egal, woher die Informationen über Mausbewegungen kommen, aber die Objekte, die die Informationen benötigen, wissen trotzdem, wo sie suchen müssen.

Angenommen, die globale Maus hat nun einen Klick auf ein Objekt bemerkt, nach deiner Beschreibung muss das Objekt selbst diese Information in der Mausklasse suchen - muss die Maus nicht das Objekt (durch Bewegung auf das Ereignis) an das Objekt melden? Wenn ja, wo bleibt dann die eingesparte CPU-Zeit? Wenn nicht, wie kommt es dann, dass dem Objekt ein Mausereignis nicht entgeht? Ich habe zum Beispiel auf eine Schaltfläche und dann auf ein Kombinationsfeld geklickt, meine Maus hat der Schaltfläche nicht mitgeteilt, dass sie angeklickt wurde, und jetzt hat die Maus das zuletzt angeklickte Objekt als Kombinationsfeld. Es muss also sein, dass die Maus ein "Objekt wurde angeklickt"-Ereignis weitergibt. Also, anstatt das Objekt angeklickt Ereignis kommt direkt von MT5 auf die Steuerklasse, es kommt auf die Maus und dann weiter an das Steuerelement, wo ist die Einsparung von CPU?

Oder übersehe ich etwas?
 

Das Mausobjekt sieht nicht selbst nach, ob es sich über einem Objekt befindet oder ob es gerade von einem Objekt benutzt wird, dies wird von den Objekten selbst erledigt. Aber das Mausobjekt ist der zentrale "Ort", an dem solche Informationen gespeichert werden können.

Die Standard-Steuerklassen arbeiten so, dass bei jeder Mausbewegung alle Objekte in einer Schleife durchlaufen werden, um herauszufinden, ob diese Bewegung etwas mit ihnen zu tun hat, das kostet viel CPU-Zeit, was man leicht sehen kann, wenn man den Taskmanager startet und einfach die Maus bewegt, wenn ein EA oder Indikator geladen ist und ein CDialog-Objekt Teil des EA oder Indikators ist. Je komplexer der Dialog ist, desto höher ist die CPU-Auslastung.

In meiner GUI, mit dem Vorhandensein eines globalen Mausobjekts, wird dies anders gehandhabt. Sie können 10000 Objekte haben und die CPU-Belastung steigt nicht an, wenn die Maus bewegt wird. Es ist so gemacht, dass nur sobald die Maustaste auf ein bestimmtes Objekt gedrückt wird, dieses bestimmte Objekt dem Mausobjekt mitteilt, dass es den Fokus hat, und sobald sich die Maus nach diesem Button-Down-Ereignis bewegt, braucht sich kein anderes Objekt darum zu kümmern, und jede weitere Bewegung der Maus / jedes weitere Mausbewegungs-Ereignis wird direkt an das Objekt geleitet, das den Fokus hat - was immer exklusiv ist - indem es seinen Zeiger benutzt.

Und da alle Chart-Objekte, egal ob zeit-/kursbasiert (Trendlinien etc.) oder pixelkoordinatenbasiert (Panels etc.) eine gemeinsame Basisklasse haben, können alle diese Objekte einen gemeinsamen Satz überladener Funktionen verwenden, um dies zu handhaben. Das ist auch der Grund, warum ich erwähnt habe, dass zwischen CWnd und CObject eine Klasse fehlt, denn diese Basisklasse dazwischen ist dieselbe Basisklasse, die auch von zeit- und preisbasierten Objekten verwendet wird, und nur so ist es möglich, effektiv zu kommunizieren und solche Ereignisse effektiv zu behandeln.

 
Sie hören also nicht mehr auf Mausbewegungen (es sei denn, sie folgen direkt auf einen Objektklick), sondern achten nur noch auf Mausklick und Mausziehen. Was den Mausklick anbelangt, so geschieht dies auf die gleiche Weise wie in der Standardlib: Das Objekt selbst erkennt den Klick, will aber auf das Ziehen vorbereitet sein, also benachrichtigt es die Maus, die wahrscheinlich ihre Position beibehält, und das weitere Ziehen wird an das Objekt zurückgegeben. Wenn die Maus zufällig die Taste anhebt, ohne zu ziehen, hört es einfach auf, sich auf das angeklickte Objekt zu konzentrieren, indem es den Objektzeiger löscht. Objekte hören also auf Klicks und die Maus hört auf Ziehen.
Es läuft also darauf hinaus, dass Mausbewegungen eigentlich als unwichtig ignoriert werden, es sei denn, kurz bevor ein Objekt angeklickt wurde?
 

Ja.

Nichtsdestotrotz habe ich die Möglichkeit, jede Bewegung aufzufangen, ob sie angeklickt wird oder nicht, und das auch mit besserer CPU-Leistung und ohne Verwendung der Objektnamen, aber das war hier nicht die Frage.

 
Ja, ich sehe jetzt das Bild, das Sie zu kommunizieren versucht haben, und sicherlich gibt es Möglichkeiten, auch Mausbewegungen von der Maus selbst zu hören, ohne dass die Objekte in einer Schleife laufen müssen. Und es kann sogar Objekte zu benachrichtigen, wenn sie im Fokus mit nur ihre Zeiger verwendet werden, wie sie als Hörer registrieren.