English Русский 中文 Español 日本語 Português
MQL5 für Anfänger: Antivandalismusschutz der grafischen Objekten

MQL5 für Anfänger: Antivandalismusschutz der grafischen Objekten

MetaTrader 5Indikatoren | 16 Mai 2016, 15:39
665 0
Dina Paches
Dina Paches

wenn Objekte aus Kunst, Kultur, öffentliche und private Eigentum
zerstört oder entweiht werden...

Wikipedia

Inhalt:


1. Einführung

Einer der Vorteile der Programmiersprache MQL5 ist, dass Codes mit den vorhandenen MQL5 Standardfunktionen geformt werden können, die verschiedene Aufgaben mit verschiedenen Arten und Zielen lösen können, wenn das Handelsterminal MetaTrader 5 verwendet ist.

Dieser Artikel wurde in der einfachen Sprache geschrieben und es wird basierend auf einfache Beispiele zwei Varianten der Gegenmaßnahmen-Realisierung betrachtet, die als Reaktion auf die Entfernung oder Änderung der grafischen Objekten im Bedienfeld des Programms durchgeführt werden. Wir zeigen, wie Sie sicherstellen können, dass es keine herrenlosen Objekte mehr im Chart gibt, nachdem das Programm gelöscht wird. Denn das Programm konnte die Kontrolle über diese Objekte verlieren, wenn jemand sie umbenannt hat.

Das Beispiel des Bedienfeldes, bevor und nach die Objekteigenschaften manuell geändert werden

in Abb. 1. Das Beispiel, wie das Bedienfeld aussieht, bevor und nach die Objekteigenschaften manuell geändert werden

Die im Artikel beschriebenen Varianten für den Bau der Reaktionsmaßnahmen gegen externe Störungen im Code können in den Situationen sehr nützlich sein, in den zum Beispiel ein Drittanbieter-Programm am Chart gestartet wird und das ist nicht direkt für die Bereinigung geeignet, kann eine Funktion für die Löschung der Objekte (ObjectsDeleteAll() oder eine selbst erstellte Funktion) verwendet werden, die durch die gesetzten Parameter funktioniert:

  • vollständige Entfernung aller Arten von grafischen Objekten im selben Fenster / Unterfenster, wo sie die Objekte sind, die manuell oder mit anderen Programmen erstellt wurden;
  • oder vollständige Entfernung die Art von Objekten, die auch im Bedienfeld Ihres Programms in vorhanden sind;
  • oder die Entfernung nach Präfix, das mit dem Präfix Ihrer Programms-Objekte entspricht.
Diese Variante sind auch aktuell, wenn es für die korrekte Arbeit des Programms erwünscht ist, die Aktionen für zufällige oder vorsätzliche Löschung seiner Bedienfelds-Objekte oder manuelle Änderung ihrer Eigenschaften im Code.

Dieser Artikel kann auch für diejenigen hilfreich sein, die gerade erst begonnen haben, die Verarbeitung der Ereignisse in der Funktion OnChartEvent() zu lernen.

Ich muss aber direkt warnen, dass dieser Artikel keine Information über die "militanten" Reaktionen-Erstellung der Codes abdeckt, deren Objekte ohne Genehmigung entfernt/geändert wurden. Der Hauptzweck der Terminalprogramme ist es - Händlersaufgaben zu lösen, und Störungen als Roboter Kriege ist es hier nicht akzeptabel.

Für diejenigen, die militanten Aktionen bevorzugen, möchte ich eine folgende Analogie machen, bevor Sie diesen Schritt in Betracht ziehen. Stellen Sie sich vor, dass eine Büroreinigerin einen Computer von jemandem Schreibtisch mit ihrem Schrubber runter geräumt hat oder den Tisch oder Computer nach ihrem Geschmack gemalt hat. Also und wenn der Besitzer, deren Eigentums beschädigt wurde, werft als Antwort all dies Geräte, Möbel und alle Anwesenden im Büro zusammen aus dem Fenster runter, wird seine Bewegung als unangemessen betrachtet. Darunter auch von dieser Person.

Bevor wir mit Beispielen zwei möglichen Reaktionsvarianten zum Vandalismus der Objekte beschreiben, wird es auch nützlich, einen der primären verfügbaren Schutz der Objekte in den Programmierungssprachen MQL5 / MQL4 zu erwähnen.


2. Einer der ersten Schutz der Objekte in MQL5/MQL4

So ohne diesen Schutz wäre der Zugriff auf Objekteigenschaften, die vom Programm erstellt werden, mehr offener.

Lassen Sie mir Ihnen erklären, was ich meine. Für den ersten Schutz der Objekte vor der Löschung oder Namen-Änderung durch ihre Eigenschaften, Beschreibung, Farben usw. gibt es und kann die Eigenschaft OBJPROP_HIDDEN verwendet werden. Er setzt oder hebt das Verbot auf, damit der grafischen Objekt-Name in der Objekt-Liste aus dem Menü des Terminals angezeigt würde: Charts -> Objekte -> Objekt-Liste. In der Standardeinstellung wird das Verbot für Objekte eingestellt, welche die Kalenderereignisse, Handelshistorie anzeigen werden, auch für Objekten, welche aus MQL5 Programmen erstellt wurden.

Wenn ein Verbot offenbar, und nicht standardmäßig gesetzt wurde, kann es schematisch im Code folgenderweise aussehen:

ObjectSetInteger(chart_id,name,OBJPROP_HIDDEN,true);

in der:

  • ObjectSetInteger — ist eine Funktion, die den Wert der entsprechenden Objektseigenschaft setzt;
  • chart_id ist der Identifikator des Charts, wo das Objekt (Null heißt das aktuelle Chart) angeordnet ist;
  • name ist der Name des Objekts, zu dem die Funktion angewendet wird;
  • true, in der Kombination mit OBJPROP_HIDDEN bedeutet die Anzeigeschließung des Objektes in der Objekt-Liste (false hebt die Anzeigeschließung auf).

Die praktische Realisierung und Abstimmung dieses Schemas im Code kann man in der Dokumentation schauen. Durch einen Klick auf den Link aus der bereitgestellten Liste von Objekten können Sie die Beispiele schauen, welche bereite Codes mit Funktionen für die Erstellung der Objekte zeigen.

Die Objekte, bei denen standardmäßig oder offenbar das Anzeigeschließungsverbot der grafischen Objekten in der Objekt-Liste eingestellt ist, kann man sehen, wenn man nur auf die Schaltfläche alle Objekten anzeigen drückt: Alle. Es wirkt als vorläufiger Schutz der graphischen Objekte vor dem manuellen Eingriff in ihren Eigenschaften durch die Objekt-Liste.

Die Objekt-Liste auf dem Chart vor dem Drücken "Alle"

in Abb. 2. Die Objekt-Liste auf dem Chart vor dem Drücken "Alle"

Die Objekt-Liste auf dem Chart nach dem Drücken "Alle"

in Abb. 3. Die Objekt-Liste auf dem Chart nach dem Drücken "Alle"

Die Tatsache, dass die Verfügbarkeit der grafischen Objekte auf dem Chart nicht vollständig verbergen werden kann, wenn man sie auch visuell unsichtbar macht, ist eher ein Vorteil als ein Nachteil. Denn man kann durch eine Liste schnell gucken, auch die Objekten-Eigenschaften ändern oder kopieren, ohne die gesamte Charts-Überprüfung, die aus mehreren Objekten und Bars der vergangenen Jahre bestehen kann. Darüber hinaus können Objekte in der Liste nach Arten, Namen und nach einigen anderen Parametern sortiert werden.

Eine von vielen weiteren Vorteilen der Trading-Terminals MetaTrader 5 und MetaTrader 4 ist die Einfachheit beim Schreiben der automatisierten Assistenten für diese Terminals und die Möglichkeit, mehrere Assistenten zu verwenden, die von anderen erstellt wurden. Aber gibt es Menschen, die sich nie irren? Man kann dazu noch unterschiedliche Kenntnisse beim Programmen-schreiben haben. So können auch die internen ethischen Grenzen sein. Die Programmiersprache, ebenso wie Menschen, kann sich mit der Zeit verändern und verbessern.

Deshalb ist die Tatsache, dass man die Bildungskorrektheit der grafischen Objekte mit einem Programm jederzeit feststellen kann, ist ein klarer Vorteil. Sie können schnell die gewünschten Objekte aus der Liste finden und ihre Eigenschaften sehen, anstatt sie im gesamten Chart suchen. Darüber hinaus können Sie sicher sein, dass das Chart keine versehentlich oder absichtlich versteckte Objekte hat, darunter diejenigen, die durch Fehler im Code enorm erzeugt werden.

Allerdings ist es wahrscheinlich, wenn die Liste aller Objekte angezeigt wird oder auch ein Teil von ihnen für die Löschung ausgewählt wird, können Sie gleichzeitig versehentlich genau die Objekte des Bedienfelds löschen, die zu diesem Zeitpunkt auf dem Chart benötigt werden.

Bevor Sie die Realisierungsvariante der Gegenmaßnahmen des Programms betrachten, verwenden wir die Vorteile der Programmiersprache von MQL4 und MQL5, die am Anfang dieses Artikels erwähnt wurden. Ich meine Codes zu erzeugen, die verschiedene Aufgaben auf verschiedene Weise lösen.


3. Die Erstellungsmethode der aufgeführten Varianten hier

Das kann Ihnen vielleicht helfen, wenn es nötig ist, einige seine Entscheidungen im Code zu erstellen und spart die Zeit auf der Suche nach Entscheidungen, daraufhin lässt es Ihnen nicht an den falschen Lösungen oder schweren Wegen geraten werden.

Um zu vermeiden, formal und akademisch zu klingen, werde ich Ihnen hier über die Methode genauso erzählen, wie ich selbst drauf gekommen bin. Die Codes, die unten erwähnt werden, sind am Ende des Artikels hinzugefügt. Für ihre Funktionalität muss man bei sich im Ordner Include des Terminals die hinzugefügte Datei ObjectCreateAndSet speichern, die im Code Base ist. Es enthält Funktionen zum Erstellen der Objekte und deren Eigenschaftsänderungen mit den notwendigen Kontrollen. Diese Datei wird nicht für die Funktionalität des angeschlossenen Indikators test_types_of_chart_events benötigt.


3.1. Das Teil der Überlegungen und Aktionen, bevor die Entscheidung bezüglich der praktischen Realisierung im Code getroffen wird

Nach der Dokumentation können Sie zur Zeit mit der Funktion OnChartEvent() die Information erhalten und verarbeiten, die über neun Arten von Ereignissen für Ihre eigenen Aufgaben/Ziele erforderlich ist, außer der Ereignissen, die generell nach Änderungen im Chart und anderen Benutzern Ereignisse sind. Einige von ihnen informieren über die Entfernung, Änderung und Erstellung der grafischen Objekte.

Zunächst einmal würde ich die Frage stellen, wie es im Code realisiert werden kann:

  • "Selbstwiederherstellung" der Objekte, wenn sie gelöscht werden oder wenn sie von jemandem manuell oder mit Hilfe eines Programms geändert werden;
  • Die "self-departure" eines Programms aus dem Chart nach solchen externen Maßnahmen.

Das alles muss gleichzeitig mit der Löschung der Objekte erledigt werden, die für das Programm aufgrund der Umbenennung "fremd" geworden sind, und auch wegen ohne zusätzliche Loops der Ereignisseverarbeitung.

Die erste Idee, die es mir kam, dass ich es in Form von Testen seiner Eigenschaften, die das Programm selbst bei den Informationslieferungen oder Objekte-Änderungen durchführt, löse, fand ich als keine optimale und vielseitige Lösung. Denn ich dachte, weil die Summe der Selbsttesten eine Menge unnötiger und nicht immer gerechtfertigter Aktionen bedeuten könnte.

Zum Beispiel während der Ereignisseverarbeitung mit Objekten wird der Name des beeinflussten Chartsobjektes mit den Namen vergleicht, die vom Programm verfolgt werden. Wenn eine Art von Ereignissen im Programm verfolgt wird, wird die Information über dieses Ereignis nicht nur nach grafischen Objekten des Programms kommen, sondern nach allen Objekten auf dem Chart. Der Name des Objekts hat den Typ string, und die Zeile-Daten werden länger als andere verarbeitet. Das Chart kann nicht mehrere Objekte haben, die manuell oder mit anderen Programmen erzeugt werden, zu den viele verschiedene Maßnahmen angewendet werden können, welche dadurch mehrere Ereignisse formen.

Im Folgenden finden Sie ein beispielhaftes Schema der Überprüfung, um die Objekten-Namen bei der aktivierten Alarm-Sendung der Ereignisse über die Löschung der grafischen Objekte zu vergleichen. Das Schema wurde ohne vorherige Verarbeitung auf die Verringerung des Vergleiches aufgeführt, die bei der Arbeit mit mehreren grafischen Objekten angewendet werden:

if(id==CHARTEVENT_OBJECT_DELETE)
        {
         string deletedChartObject=sparam;
         //---
         for(int i=QUANT_OBJ-1;i>=0;i--)
           {
            if(StringCompare(deletedChartObject,nameObj[i],true)==0)
              {
            /*hier ist der Code mit Aktionen, wenn der Objektname
            , der nach dem Ereignis gekommen sind, mit dem   Objektnamen des Programms vollständig
            zusammengefallen sind*/
               return;
              }
           }
        }

Darüber hinaus wird die Variante mit "Revision" (basierend auf Ereignisse oder Perioden) das Problem bei der Objekte-Umbenennung von jemandem nicht lösen, und schließlich kann das Programm die Kontrolle über sie verlieren, dadurch lässt er "herrenlose" Objekte am Chart.

Deshalb habe ich mir die Verwendung und Detaillierung der Flaggensysteme überlegt. Ähnlich dem Alarm, wo eine Semaphor-Flagge gleich 0 ist, bedeutet es zum Beispiel, dass die Änderung und Löschung der Codes der Objekte vom Programm als unbefugte externe Störungen behandelt werden muss. Bei den vom Code vorgesehenen Aktionen der Objekteänderung oder Löschung wird der Wert der Flagge um einen anderen Wert ändern, damit die Aktion die Änderung-Löschung nicht als "fremde Zugriff" wahrgenommen würde.

Allerdings, da aus Ereignisse im Chart eine Reihe mit ihrer weiteren Erarbeitung in OnChartEvent()gebildet wird, war in dem Moment nicht klar, ob ein Flagge-Alarmsystem in der Gestaltung des Codes "Self-Recovery" für solche Fälle ist. Auch zu vermeiden, Loops und einfach zusätzliche wiederholte Loops erzeugt zu haben, die bei der Verarbeitung der Ereignisse-Löschung dieser Art von Aktion entstehen.

Zum Beispiel, es gibt ein Bedienfeld, das aus ein Paar Objekten besteht, aber im Verarbeitungscode der Ereignisse-Löschung im Bedienfeld wurde die Informationslieferung mit Print() hinzugefügt. Das Bedienfeld über diese Ereignisse-Benachrichtigung kann leicht die Log-Datei, während der häufig kontinuierlichen Selbstwiederherstellung auf dem Chart, mit mehreren Noten innerhalb von Sekunden bei dem Self-Recovery Objekt füllen. Und dies trotz der Vorauswahl über den Namen, wenn die Flagge-Semaphor und Selbstwiederherstellung mit dem folgenden Verfahren (oder gleichwertig) angewendet werden:

else  if(id==CHARTEVENT_OBJECT_DELETE)
     {
     if(flagAntivandal==0)
        {
            string deletedChartObject=sparam;
            //---
            for(int i=QUANT_OBJ-1;i>=0;i--)
              {
               //---  Aktionen, wenn Namen vollständig zusammenfallen:
               if(StringCompare(deletedChartObject,nameObj[i],true)==0)
                 {
                  //--- Die Sendung für Ausdrucken in "Experten" des Terminals:
                  TEST_PRINT(deletedChartObject);
                  //--- Schalten das  "Alarm" für die Operation "Freundlich" des Programms aus
                  flagAntivandal=-1;
                  //--- Löschen wir übrige Objekte:
                  ObjectsDeleteAll(0,prefixObj,0,-1);
                  //--- Erstellen das Bedienfeld neu
                  PanelCreate();
                 //--- Erneuern das Chart 
                  ChartRedraw();
                 //--- Wiedergabe der Flagge für den "Schutz" der Objekte:
                  flagAntivandal=0;
                  return;
                 }
              }
         return;
        }
      return;
     }//else  if(id==CHARTEVENT_OBJECT_DELETE)

Bei einer solchen Code-Aufnahme werden die Löschung und die Erstellung der Objekte geschleift, um einen Strom von Ereignissen zu bilden. Und die Entfernung der anderen Bedienfeldesobjekte wird zur anschließenden Selbstwiederherstellung erforderlich sein, beispielsweise, wenn das Segeltuch mit anderen Objekten (Schaltflächen, Eingabefelder usw.) versehentlich oder absichtlich gelöscht werden und es muss mit keinen anderen überlappten Objekt neu erstellt werden.

Wenn Ihr Computer nicht genügend Speicherplatz hat, dann empfehle ich nicht den oben genannten Code praktisch zu testen. Wenn ja, dann können Sie es selbst testen, indem Sie es vollständig mit Ereignissen von der Löschung und Änderung im beigefügten Testcode test_count_click_2 ersetzen.

Ich habe nicht die maximale Kapazität für das Auffüllen einer Protokolldatei als Ergebnis der Verwendung einer falschen Flagge geprüft, weil ich das Terminal 2-3 Sekunden nach dem Ereignis über eine falsche "Selbstwiederherstellung" zum Herunterfahren gezwungen hatte, dabei habe ich "blinken" der Programmsobjekte und schnelle, unendliche Notizen im Tab "Experten" des Terminals beobachtet. Ich löschte die deutlich erhöhte Protokolldatei und reinigte den Papierkorb.

Darüber hinaus blieb die Lösung zu diesem Zeitpunkt unbekannt, falls Objekte in dem Code umbenennt werden. Es fehlte ein "Anker", der in dieser Situation helfen könnte.

Deshalb habe ich meinen Speicher mit Informationen über die Ereignisse-Arten des Charts aus der Dokumentation aktualisiert, und habe die Beschreibung der Funktion ObjectSetString() geguckt, wo es geschrieben ist, dass ein Objekt zwei Ereignisse nach dem Umbenennen gleichzeitig bildet:

  • Löschung der Objekte mit den alten Namen,
  • das Erstellen des grafischen Objekts mit einem neuen Namen.

Nach dem Lesen des Titels Objekteigenschaften habe ich mich entschieden, dass ein solcher Anker in Form der Erstellungszeit werden kann, die durch die Eigenschaft OBJPROP_CREATETIME bestimmt werden kann.

Zum Beispiel, wie Sie aus dem beigefügten Skript test_get_objprop_createtime sehen können, entspricht die Erstellungszeit des Objektes der lokalen Zeit des Computers, auf dem das Terminal läuft:

Die Erstellungszeit des Objektes entspricht der lokalen Zeit des Computers, im Moment das Objekt erstellt wird

in Abb. 4. Die Erstellungszeit des Objektes entspricht der lokalen Zeit des Computers, im Moment das Objekt erstellt wird

Ein genanntes Testskript erstellt eine Schaltfläche auf dem Chart, bestimmt die Zeit seiner Erstellung und druckt sie über Print() im Protokoll des Titels Experten. Er setzt und druckt verschiedene Arten der Zeit in den gleichen Titel des Terminals: die lokale Zeit des Computers, die aktuelle Zeit des Handelsservers, die letzte bekannte Zeit des Servers nach der kommenden Notierungszeit, die GMT-Zeit. Dann "friert" es für 10 Sekunden und löscht die erstellte Schaltfläche aus dem Chart, damit sein Betrieb beendet wird.

Der nächste Schritt ist, einen Aktionsplan zu machen, für eine klare Formulierung von Lösungen bei der nachfolgenden Codeerzeugung. Diese abschließenden Lösungen müssen vielseitig genug sein, damit es in der Zukunft nicht notwendig wäre, getrennte Wiederherstellungsmaßnahmen für "jede Schaltfläche" zu schreiben. Sie müssen auch ein Prinzip der friedlichen Koexistenz auf dem Chart berücksichtigen.


Der Aktionsplan bestand aus den folgenden Punkten:

3.1.1. Um zu überprüfen, welche Ereignisse und in welcher Reihenfolge sie für ein Drittanbieter-Programm angezeigt werden als unabhängiger Beobachter, und für ein Programm, dessen Objekte extern beeinflusst werden:

  • wenn die Eigenschaften eines Grafikobjekts manuell durch das Dialog der Eigenschaften und mit einem anderen Programm geändert werden;
  • wenn das Objekt durch "Liste der Objekte" manuell und mit einem anderen Programm gelöscht wird;
  • wenn ein Objekte manuell durch das Dialog der Eigenschaften und mit einem anderen Programm umbenennt wird.

Zur gleichen Zeit ist es notwendig, die Erstellungszeit der Objekten anzuzeigen und die erzielten Ergebnisse als Tabellen aufzuschreiben.

Dementsprechend wird das Folgende erforderlich, um den ersten Punkt des Plans zu realisieren:

3.1.2. Ein vom Programm eingebauter Indikator-Assistent, der als externer Beobachter fungiert und beschreibt die Ereignisse aus dem Chart.

Ich entschied mich für den Indikator, um den Expert Advisor auf dem Chart zur gleichen Zeit mit seiner Funktionalität zu starten.

Ich werde dieser Assistent nicht gründlich betrachten, sein vollständiger Code wird in der Datei unter dem Namen test_types_of_chart_events angehängt. Da es für Sie jedoch in der Zukunft nützlich sein könnte, wenn Sie sich mit Ereignissen beschäftigen, werde ich hier folgendes erwähnen:

  • Dieser Indikator ist vorgesehen, mit neun Arten von Standard-Ereignissen zu arbeiten.
  • Es zeigt den Ereignis-Namen und mit ihm erhaltenden Wert: id, lparam, dparam, sparam (Der Objekt-Name bei Ereignissen mit grafischen Objekten).
  • Die Benachrichtigungen über einige Ereignisse können aktiviert/deaktiviert werden, deshalb testen Sie ihn mit einem separaten Chart, wo keine Trading-Programme zu diesem Zeitpunkt beim Start dieses Test-Codes funktionieren. Andernfalls können Sie Benachrichtigungen deaktivieren, die für die korrekte Arbeit dieser Programme erforderlich sind.

    Externe benutzerdefinierte Eigenschaften eines Testindikator-Beobachters

in Abb. 5. Externe benutzerdefinierte Eigenschaften eines Testindikator-Beobachters

Der Indikator hat Benachrichtigungen über Ereignisse standardmäßig deaktiviert, die zu den Aktionen mit Objekten nicht direkt miteinander verknüpft sind. Es ist die Anzeigen vorgesehen, Benachrichtigungen für fünf von neun Arten der Standardereignissen aktiviert / deaktiviert zu haben, mit den er arbeitet.

  • Außerdem zeigt dieser Test-Code Informationen auf dem Titel des Handelsterminald Experten mit der Funktion Print(). Also, um zu vermeiden, mit einer großen Menge der eingehenden Daten die Log-Dateien des Terminals zu überfluten, werden durch diesen Indikator die Ereignisse CHARTEVENT_MOUSE_MOVE deaktiviert, die das Bewegen und Klicken der Maus anzeigen. Die Einschaltung der Anzeige von Informationen über diese Art von Ereignissen wird in dem Testindikator des Codes nicht zur Verfügung gestellt.

3.1.3. Die andere Assistenten in Experimenten:

  • Das Skript, das die grafischen Objekte Schaltfläche und Eingabefeldauf dem Chart erzeugen;
  • Das Skript, das die angegebenen Eigenschaften der Objekte durch den Namen ändert und löscht die Objekte, die es sich nach einer Pause geändert hat.


3.2. Die Ergebnisse der durchgeführten Experimente

Die Ergebnisse sind in der Tabelle unten angezeigt. Das Programm, dessen Objekte unter Aktionen betroffen werden, "sieht" Standard Benachrichtigungen über Ereignisse genauso, wie andere Programme auf dem Chart, was der Grund ist, warum nur eine Tabelle vorgesehen ist. Es basiert auf Aktionen mit Objekten "Schaltfläche" und "Eingabefeld".

Aktion mit einem Objekt id lparam dparam sparam Der Ereignisname, der über die Aktion benachrichtigt, die manuell gemacht wurden Die Erstellungszeit ** Der Ereignisname, der über die Aktionen benachrichtigt, die von seinem Programm und dem fremden Programm gemacht wurden
Die Erstellungszeit **
Das Erstellen des neuen Objekts (nicht wegen der Umbenennung). 7
0 0 Der Objekt-Name CHARTEVENT_OBJECT_CREATE Die lokale Zeit des Computers, auf dem das Terminal läuft CHARTEVENT_OBJECT_CREATE Die lokale Zeit des Computers, auf dem das Terminal läuft
Die Umbenennung des Objekts (Das Objekt wird dabei mit dem vorherigen Namen gelöscht und ein neues Objekt wird zur gleichen Zeit erstellt)
6

7

8
0

0

0
0

0

0
Der Objekt-Name,
Der Objekt-Name,
Der Objekt-Name
CHARTEVENT_OBJECT_DELETE

CHARTEVENT_OBJECT_CREATE

CHARTEVENT_OBJECT_CHANGE
Bei dem neuen Objekt ist die Erstellungszeit des Objektes gleich mit dem vorherigen Es gibt keine Benachrichtigungen
Bei dem neuen Objekt ist die Erstellungszeit des Objektes gleich mit dem vorherigen
Die Änderung des Objekt-Hintergrunds 8 0 0 Der Objekt-Name СHARTEVENT_OBJECT_CHANGE ändert sich nicht Es gibt keine Benachrichtigungen ändert sich nicht
Die Änderung der Objekt-Koordinaten in der Achse X 8 0 0 Der Objekt-Name СHARTEVENT_OBJECT_CHANGE ändert sich nicht Es gibt keine Benachrichtigungen ändert sich nicht
Die Löschung des Objektes 6 0 0 Der Objekt-Name CHARTEVENT_OBJECT_DELETE *** CHARTEVENT_OBJECT_DELETE ***

 

Tabelle 1. Ein Teil davon, welches ein freundliches und ein fremdes Programm bei Benachrichtigungen über Erstelunngsereignisse, Veränderungen, Löschungen der Objekten auf dem Chart "sehen" kann


Hinweis:

* Während eine Ereignisbenachrichtigung im Programm verarbeitet wird, können andere Meldungen, die während oder nach dieser Verarbeitung gekommen sind, bilden in diesem Programm eine Reihe für die Verarbeitung.

** Ich habe bemerkt, wenn ein Chart Grafikobjekte enthält, die nicht durch das Programm neu erstellt werden, nachdem das Terminal neu gestartet wird, dann wird die Erstellungszeit dieser Objekte der Funktion OBJPROP_CREATETIME nach dem Neustart zurückgesetzt, welche 1970.01.01 00:00:00 entspricht. Das heißt, die vorherige Zeit wird "Reset". Dies geschieht auch mit den Chartsobjekte, die manuell gesetzt werden. Wenn Sie Timeframes umschalten, wird die Erstellungszeit der Objekte nicht zurückgesetzt.

*** Wenn Sie versuchen, die Erstellungszeit des Objekts zu bestimmen, unter Verwendung von OBJPROP_CREATETIME, dann, weil das Objekt bereits gelöscht ist, erscheint die Benachrichtigung über den Fehler 4203, die bedeutet, dass es ein falscher Identifikator der Eigenschaften vom grafischen Objekt angewendet wurde.

Wenn Eigenschaftsänderungen vom Programm ausgeführt wurden, wird keine solche Meldung anzeigt. Natürlich ist es klar, dass es für das Gute getan wurde. Da nur in einem einzelnen Chart des Terminals können viele Programme funktionieren, einschließlich derjenigen, die mehrere Aktionen mit einer Reihe von grafischen Objekten durchführen, und es können viele offene Charts mit diesen Programmen sein. Also ich gehe davon aus, dass die Benachrichtigungen für Programme, in denen die Ereignisverarbeitung zu jeder programmatischen Änderung der Eigenschaften eines Objekt-Charts angewendet wird, führt zu einer erheblichen Zunahme des Verbrauchs von Ressourcen.

Um zu vermeiden, Benutzer mit einem Standardsatz von Ereignisbenachrichtigungstypen zu beschränken, haben die Entwickler für uns eine Möglichkeit gegeben, persönliche Mitteilungen im Code bei jedem einzelnen bestimmten Ereignis zu erstellen. Dafür wird die Funktion EventChartCustom() verwendet und die erzeugt Benachrichtigungen über die angegebenen benutzerdefinierten Ereignisse für ihr eigenes oder alle Charts des Terminals.

Gemäß den Testsergebnissen wurden einige vielfältige Lösungen vorgeschlagen.

Sie können sicherlich keine mögliche Panazee gegen allerlei Unglück sein. Aber ich glaube, dass sie ihre Aufgaben für die Bedienfeldsobjekte fähig erfüllen können, und sie können auch bei der Entwicklung Ihrer eigenen Optionen nützlich sein.

Diese Lösungen basieren sich auf:

  • auf die Anordnung der Flags im Code, einschließlich adaptiver, je nachdem, welche Aufgaben es gibt;
  • auf die Funktionalität der speziellen Funktionen, die als Teil der Systemen für Konstruktionsvarianten aufgeführt werden.

Das Allgemeine für diese Lösungen ist das Folgende. Unabhängig davon, ob es erforderlich ist, den "Schutz" für eine oder alle Objekte eines Bedienfeldes zu organisieren, für die Realisierung der Varianten von Objekten Selbstwiederherstellung und / oder Programme, die "self-departure" sind, müssen Sie im Code berücksichtigt werden:

  • Die Variablen für die Speicherung der Flaggen, die im Programm im globalen Bereich der Variablen-Sichtbarkeit erklärt werden, sind außer der Funktionen, das heißt, die sind bis zum Block der Funktion OnInit() (nicht zu verwechseln mit den globale Variablen Terminals).
  • Die Erstellung eines gemeinsamen nicht kurzen Präfix für "geschützte" Objekte in ihren Namen.
  • Die Einschaltung der Benachrichtigungen über die Objektlöschungen in den Chartseigenschaften (CHART_EVENT_OBJECT_DELETE), wenn diese Eigenschaft aus ist.
  • Die Einstellung der Frequenz des Timers, und dementsprechend auch das Hinzufügen zum Code der Funktion OnTimer(), wo die Kontrolle durch Benachrichtigungen über Löschung von Objekten nach einer voreingestellten Zeit durchgeführt werden. Der Timer wird in der Funktion OnDeinit() mit Hilfe von EventKillTimer() gestoppt.
  • Das Vorhandensein im Code, im Körper der Funktion OnChartEvent() der Verarbeitungsblöcke der Benachrichtigungen über die Ereignissen CHARTEVENT_OBJECT_CHANGE und CHARTEVENT_OBJECT_DELETE mit gegebenen Aktionen spezifizieren sich für ungekündigte Eingriffe.

Die Realisierungsvariante der Löschung des Charts aus den umbenannten Objekten, die die Objekte des Programms waren, sollte folgendes vorgesehen haben:

  • Wenn es eine Menge der Objekten gibt, wird die Zeit der "geschützten" Objekte im Datenfeld bestimmt und gespeichert, oder in regulären Variablen, wenn es nur wenige geschützte Objekte gibt.
  • Spezifische Funktionen für die Löschung der Objekte, einschließlich der Löschung der Objekte nach ihrer Erstellungszeit.

Darüber hinaus ist wichtig die Reihenfolge der Realisierung der "sicherheiten" Aktionen im Code.

Wenn Sie in dem Code nur ein Programm der "Self-departure" aus dem Chart durch nicht autorisierten Änderungen / Löschungen der Objekten konstruieren, dann, je nach der Aufgabenstellung kann eine einzige Variable für eine Flagge ausreichend sein. Bei Werten, zum Beispiel:
  • -1: Deaktivieren des "Alarms" vor der Aktion im Code, die vermutlich da durchgeführt wird. Um die restlichen Verarbeitungen am Codeanfang der Blocken von Entfernung und Änderungsereignissen return bei dem Wert der Flagge. Also, in der Tat bedeutet es, die eingehenden Benachrichtigungen über Entfernung und Änderungsereignissen der Objekte zu ignorieren, indem Sie die Verarbeitungsblöcke der Benachrichtigungen über solche Ereignisse bei dem Wert der Flagge verlassen:
if(flagAntivandal==-1){return;}
  • 0: Aktivieren des "Alarms" für den Schutz der Objekte (allen oder einen Teil von ihnen). Es wird gesetzt, wenn der "Alarm" nach der Durchführung der "freundlichen" Aktionen mit Objekten aktiviert wird. Parallel als "Sicherheit" Maßnahmen in den Blöcken des Codes für die Änderung oder Entfernung des Objektes wird die nächste Reihenfolge der Operationen verordnet:
    • wenn beim Wert der Flagge 0 eine Benachrichtigung über Löschung oder Änderung eines Objektes gekommen ist, so wird zuerst überprüft, daß das Ereignis mit einem der "geschützten" Objekte stattgefunden hat;
    • wenn das Ereignis mit einem der "geschützten" Objekte stattgefunden hat, dann, bevor weitere Schritte gemacht werden, sollten Sie den "Alarm" der Flagge deaktivieren, indem Sie den Wert auf -1 ändern, so wird die Code-Loop vermieden, wenn das Programm vom Chart gelöscht wird;
    • Erst nach diesen vorläufigen Maßnahmen wird die Funktion der Löschung des Programms aus dem Chart angewendet, die mit dem unter stehenden Mittel erstellt wurde:
      • ChartIndicatorDelete() für den Indikator. Ein Kurzname für den Indikator muss in OnInit() im Voraus eingestellt werden:
IndicatorSetString(INDICATOR_SHORTNAME,short_name);
  • ExpertRemovе() für den EA. Wenn Sie diese Funktion noch nicht kennen, dann geben Sie bitte acht auf Dokumentation für ihre Beschreibung und auf das aufgeführte Beispiel.

Mindestens zwei Flaggen werden benötigt, wenn Sie ein Objekt "Selbstwiederherstellung" nach einem fremden Eingriff in den Code planen, in dem Objekte gelöscht und statt sie neu Objekte erstellt werden. Einer von ihnen ist in der vorherigen Flagge in ihrer Funktion gleich. Der zweite ist dafür erforderlich, um die Code-Loop von einer möglichen Lieferung der Löschungsereignisse während der "Wiederherstellungsmaßnahmen des Objektes zu verhindern. Die Maßnahmen hier werden etwas mehr kompliziert. Diese zweite Flagge ist adaptiv und dient für eine automatische Selbsteinstellung des "Alarms" und die Verarbeitung der Ereignisse von der Löschung der Objekte. Es "entladet" die unnötige Ereignisverarbeitung. Gründlicher betrachten wir es im Beispiel vom Schema 4.2.

Nun lassen Sie uns die Beispiele erklären, die bereits erwähnt wurden.


4. Die Schemen der Realisierungsvarianten bei unbefugter Änderung oder Entfernung der Programm-Objekte

Das Beispiel einer gleichzeitigen Realisierung im Code einer "Selbstwiederherstellung" in Bezug auf einige Objekte und ein "self-departure" aus dem Chart beim Änderungen / Löschung von anderen Objekten werden im 5-en Kapitel dieses Artikels aufgeführt. Es beschreibt das Codeschema des operationalen Programms, das bei Bedarf auch Ihren Assistent werden kann.

Wir werden mit dem Beispiel eines weiteren Testcodes von einfachen bis zu komplexen Sachverhalten erklären, die auf dem Chart ein Feld für die Berechnung der Mausklicks auf seine Objekte erstellt, der zu den Bereichen "Ja" und "Nein" gehört.

Dies ist, wie das Feld des Testcodes je nach der Sprache des Handelsterminals aussieht

in Abb. 6. Das Feld des Testcodes je nach der Sprache des Handelsterminals

Dies ist ein einfacher Testcode, basierend auf ihm wird es einfacher, die unten gebrachten Betriebssysteme von zwei folgenden Aktionstypen zu verfolgen:

Der ursprüngliche Code des Testindikators ohne unten beschriebene Systeme wird zum Artikel unter dem Namen test_count_click_0 hinzugefügt. Während der Durchführung der beiden folgenden Schemen wurden zwei Arten dieses Testcodes mit der Rücksicht auf die gebrachten Ergänzungen erstellt. Aus diesem Grund können Sie die Arbeit jedes Systems sofort einzeln in Form von einem ganzen Code sehen, und auch deren Betrieb auf dem Chart durch die Löschung oder Änderungen der Objekte dieses Codes testen.

Die zusätzlichen Zeilen mit dem Hinweisen auf Print() sind in den beigefügten Codes enthalten, wo diese Regelungen realisiert werden, so dass Sie die Reihenfolge der Verarbeitung bei selbstständigen Änderungen oder Entfernungen der Objekte sehen könnten. Im Folgenden sind die Codezeilen ohne zusätzliche Ausgabebefehle auf Print().


4.1. Die "self-departure" des Programms aus dem Chart mit der Löschung der geänderten Objekte

Die Vollversion eines Arbeitstestcode wird unter dem Namen test_count_click_1 hinzugefügt.

4.1.1. Die Dateierstellung mit diesem Schema im Code:

Die Datei test_count_click_0 wird unter dem Namen test_count_click_1 gespeichert. Dies kann durch die Öffnung der hinzugefügten Datei mit der Nummer 0 getan werden, und dann durch das Hauptmenü des MetaEditor: Datei -> Speicher unter...

4.1.2. Die Variablen, die über alle Funktionen im Rahmen der Sichtbarkeit für alle Programmteile deklariert werden, das heißt, bis der Block der Funktion OnInit():

Der Name des Indikators in #define wurde für eine nachfolgende interne Substitution ersetzt:

#define NAME_INDICATOR             "count_click_1: "

Die Variable wird für den Semaphor-Flagge hinzugefügt:

int flagAntivandal;
Es wurde ein Array zum Speichern der Zeiten von Objekten hinzugefügt, deren Größe gleich der Menge der "geschützten" Objekte ist:
datetime timeCreateObj[QUANT_OBJ];

Ein Text-Array wurde zum Speichern zwei Warnmeldungen hinzugefügt, wenn der Indikator der "self-departure" von dem Chart durchführt. Das erste, wenn die Löschung aus dem Chart erfolgreich stattgefunden hat, und die zweite - wenn ein Fehler während dieser Operation auftritt. Das Array wird im Rahmen der Sichtbarkeit für alle Programmsteile erklärt, da der Ausgang dieser Nachrichten in zwei Sprachen (Englisch und Russisch) vorgesehen ist, je nach der Sprache des Terminals.

string textDelInd[2];

Weiterhin können in diesem Array gespeicherten Nachrichten nützlich sein, wenn es vorgesehen wird, dass der Indikator wegen des Empfangs des REASON_INITFAILED Deinitialisationsgrunds im Code OnInit() das Chart verlässt.

4.1.3. Die Funktion LanguageTerminal(), die ist für die Texte der Nachrichten je nach der Sprache des Handelsterminals verantwortlich:

Werden Texte der Nachrichten beim erfolgreichen und nicht erfolgreichen "self-departure" aus dem Chart hinzugefügt.

void LanguageTerminal()
  {
   string language_t=NULL;
   language_t=TerminalInfoString(TERMINAL_LANGUAGE);
//---
   if(language_t=="Russian")
     {
      textObj[3]="Ja: ";
      textObj[4]="Nein: ";
      textObj[5]="Всего: ";
      //---
      StringConcatenate(textDelInd[0],"  Der Indikator konnte nicht gelöscht werden: \"",
                        prefixObj,"\". Der Code des Fehlers: ");
      StringConcatenate(textDelInd[1]," Der Indikator wurde vom Chart gelöscht: \"",
                        prefixObj,"\".");
     }
   else
     {
      textObj[3]="Yes: ";
      textObj[4]="No: ";
      textObj[5]="All: ";
      //---
      StringConcatenate(textDelInd[0],"Failed to delete indicator: \"",
                        prefixObj,"\". Error code: ");
      StringConcatenate(textDelInd[1],
                        "Withdrew from chart indicator: \"",
                        prefixObj,"\".");
     }
//---
   return;
  }

4.1.4. In der Funktion PanelCreate(), welche die Objekte des Bedienfelds erstellt:

Nach der Erstellung der Objekte wird ihre Erstellungszeit bestimmt und es wird im Array gespeichert. In einer einfachen Version kann dies so aussehen:

void PanelCreate(const long chart_ID=0,const int sub_window=0)
  {
   for(int i=NUMBER_ALL;i>=0;i--)
     {
      //--- Das Feld für die Anzeige der Anzahl der Klicks:
      if(ObjectFind(chart_ID,nameObj[i])<0)
        {
         EditCreate(chart_ID,nameObj[i],sub_window,X_DISTANCE+WIDTH,
                    Y_DISTANCE+(HEIGHT)*(i),WIDTH,HEIGHT,
                    textObj[i],"Arial",FONT_SIZE,"\n",ALIGN_RIGHT,true,
                    CORNER_PANEL,clrText[i],CLR_PANEL,CLR_BORDER);
         //--- Bestimmen und schreiben die Erstellungszeit des Objektes:
         CreateTimeGet(chart_ID,nameObj[i],timeCreateObj[i]);
        }
     }
//---
   int correct=NUMBER_ALL+1;
//---
   for(int i=QUANT_OBJ-1;i>=correct;i--)
     {
      //--- Die Felder mit begleitenden Anmerkungen:
      if(ObjectFind(chart_ID,nameObj[i])<0)
        {
         EditCreate(chart_ID,nameObj[i],sub_window,X_DISTANCE+(WIDTH*2),
                    Y_DISTANCE+(HEIGHT)*(i-correct),WIDTH,HEIGHT,
                    textObj[i],"Arial",FONT_SIZE,"\n",ALIGN_LEFT,true,
                    CORNER_PANEL,clrText[i-correct],CLR_PANEL,CLR_BORDER);
         //--- Bestimmen und schreiben die Erstellungszeit des Objektes:
         CreateTimeGet(chart_ID,nameObj[i],timeCreateObj[i]);
        }
     }
   return;
  }

4.1.5. Die Variante der Funktion, um die Erstellungszeit des Objektes in der Variable zu bestimmen und zu schreiben:

bool CreateTimeGet(const long chart_ID,
                   const string &name,
                   datetime &value
                   )
  {
   datetime res=0;
   if(!ObjectGetInteger(chart_ID,name,OBJPROP_CREATETIME,0,res))
     {
      Print(LINE_NUMBER,__FUNCTION__,", Error = ",
            GetLastError(),", name: ",name);
      return(false);
     }
   value=res;
   return(true);
  }

Falls das Programm auf dem Chart während des Wiederanlaufs im Notfall des Terminals war, beispielsweise wegen einer Abstürzung, wird eine Revisionsfunktion der Erstellungszeit der Objekte hinzugefügt:

bool RevisionCreateTime(int quant,datetime &time_create[])
  {
   datetime t=0;
   for(int i=quant-1;i>=0;i--)
     {
      t=time_create[i];
      if(t==0)
        {
         Print(LINE_NUMBER,__FUNCTION__,", Error create time: ",
               TimeToString(t,TIME_DATE|TIME_SECONDS));
         return(false);
        }
     }
//---
   return(true);
  }

Der Aufruf der Funktion wird in OnInit() nach PanelCreate() platziert.

Ich gehe davon aus, wenn nach der Notschließstellung des Terminals und anschließend sein Neustart gibt diese Funktion false zurück, dann, bevor es geschieht, kann eine Fehlermeldung 4102 von der Funktion CreateTimeGet() im Titel "Experten" erscheinen, was darauf hinweist, dass das Chart nicht reagiert.

4.1.6. Im Block der Funktion OnInit():

4.1.6.1. Bevor die Funktion für die Erstellung des Bedienfeldes kommt, wird die hinzugefügte Semaphor-Flagge mit dem Wert -1 initialisiert. Es bedeutet, dass der Alarm für die Zeit der Ausführung der "freundlichen" Aktionen mit Objekten deaktiviert wird. Darunter ist auch dafür, um die unerwartete Überraschungen bei der Timeframes-Abwechslung im Chart zu vermeiden.

flagAntivandal=-1;

4.1.6.2. Es wird ein Kurzname des Indikators gesetzt, wenn es noch nicht gemacht wurde. Es wird dafür benötigt, wenn das Programm aus dem Chart zwangsweise gelöscht wird.

Im vorgesehenen Beispiel des Testcodes wurde der Kurzname des Indikators schon festgelegt und war gleich dem Prefix des Objektes, das aus dem Namen, Symbol, und Timeframes des Indikators bestand, worauf er eingestellt wird:

//--- Erstellen wir die Prefix für Objekt-Namen des Codes und den Kurznamen des Indikators:
   StringConcatenate(prefixObj,NAME_INDICATOR,Symbol(),"_",EnumToString(Period()));
//--- Es wird ein Kurzname des Indikators gesetzt:
   IndicatorSetString(INDICATOR_SHORTNAME,prefixObj);

4.1.6.3. Nach der Erstellung des Bedienfelds und der Arraysrevision mit der Erstellungszeit der Objekte aktivieren wir den "Schutz" Alarm:

//--- Erstellen wir das Feld:
   PanelCreate();
/*Die Revision des Arrays von der Erstellungszeit der Objekte bis zum Arbeitsende
des Programms, wenn etwas schief geht:*/
   if(!RevisionCreateTime(QUANT_OBJ,timeCreateObj))
     {return(REASON_INITFAILED);}
/*Setzen wir die Flagge in den Reaktionsszustand
auf die Löschung und Änderung der Objekte:*/
   flagAntivandal=0;

4.1.6.4. Aktivieren die Benachrichtigungen über die Löschungsereignisse der grafischen Objekte, wenn es in Eigenschaften deaktiviert ist:

//--- Die Aktivierung der Benachrichtigungen über die Löschungsereignisse der grafischen Objekte
 bool res=true;
 ChartEventObjectDeleteGet(res);
 if(res!=true)
 {ChartEventObjectDeleteSet(true);}

Hinweis: ChartEventObjectDeleteGet() und ChartEventObjectDeleteSet() — sind bereite Funktionen mit Beispielen der Arbeit mit Charts in Dokumentation.

4.1.6.5. Bevor wir das OnInit() verlassen, setzen wir die Überprüfungsperiode für den Timer in Sekunden, wenn Benachrichtigungen über Ereignisse von Löschungen der Objekte in den Chartseigenschaften während der Programmsfunktionalität deaktiviert werden:

EventSetTimer(5);

4.1.7. Im Block der Funktion OnDeinit():

Wir schreiben den "Alarm" zu deaktivieren:

flagAntivandal=-1;

Schreiben wir den Stopp der Ereignisseerzeugung vom Timer:

EventKillTimer();

Die Löschung des Indikators, wenn es von OnInit() der Deinitialisationsgrund im Code REASON_INITFAILED kommt:

//--- Die Löschung des Indikators, wenn es von OnInit()die REASON_INITFAILED kommt.
   if(reason==REASON_INITFAILED)
     {
      ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
     }

4.1.8. Im Block der Funktion OnTimer():

Mit Kopieren und Einfügen replizieren die Codezeilen vom Punkt 4.1.6.4 zu aktivieren, um Benachrichtigungen über Ereignisse von Objekten auf dem Chart nach dem Timer zu löschen, falls sie von einem anderen Programm gesperrt werden.

4.1.9. Erstellung der Aktionen in der Funktion OnChartEvent():

4.1.9.1. Wenn es nicht vorgesehen ist, bei Ereignissen keine Änderung oder Löschung der Objekte zu haben, dann können diese Ereignisse in einem Block zusammengefasst werden.

4.1.9.2. Dann macht man als erste, die Flagge zu überprüfen, ob der "Alarm" bei einer Benachrichtigung über das Ereignis der Änderung / Löschung von Objekt aktiviert ist. Wenn der Wert der Flagge gleich -1 ist (der "Alarm" ist deaktiviert), dann verlässt es aus dem Block der Ereignisseverarbeitung.

4.1.9.3. Wenn der Wert der Flagge 0 ist (Der "Alarm" ist aktiviert), können Sie zunächst die Prüfung für das Zusammenfallen der Objektenamen starten, die in der Meldung dem Präfix-Programm-Objekte kam. Die Funktion StringFind() wird für diesen Zweck verwendet, so besteht keine Notwendigkeit, das gesamte Array der Programmobjektennamen mit jeder Benachrichtigung über Änderungen und Löschungen der Objekte aus dem Chart zu sortieren. In diesem Fall wird ein Prefix in OnInit() nicht kurz gesetzt, und dadurch bekommt man einen guten Filter. Die Prefix-Bildung wird in p.4.1.6.2 gezeigt.

Wenn es kein Zusammenfallen mit Präfix gibt, wird es aus dem Block der Ereignisseverarbeitung verlassen.

4.1.9.4. Wenn es ein Zusammenfallen mit Präfix gibt, nur dann wird die Überprüfung der empfangenen Benachrichtigungen über das Zusammenfallen der Namen mit "geschützten" Programmen der Objekte durchgeführt. Wenn Namen vollständig gleich sind, wird ein Wert der Schutzflagge um -1 (deaktivieren) geändert, um zu verhindern, zusätzliche Loops zu erzeugen, wenn ein Programm aus dem Chart gelöscht wird.

4.1.9.5. Falls es ein Objekt gibt, das "ungebrauchtes" wegen der Umbenennung geworden ist, wird eine Suche nach Objekten mit der gleichen Erstellungszeit, die genauso wie bei der angegebenen war, durchgeführt, mit einer weiteren Entfernung, falls es gefunden wird.

4.1.9.6. Erst dann wird das Programm vom Chart entfernt.

Die beschrieben Aktionen werden im Code erstellt:

else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)
     {
      if(flagAntivandal==-1)//Das Ereignis ignorieren, wenn der "Alarm deaktiviert ist"
        {return;}
      else if(flagAntivandal==0)//wenn der "Alarm" aktiviert ist
        {
         //--- Schauen wir auf das Zusammenfallen nach Präfix:
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)//wenn ein Zusammenfallen nach Präfix gibt
           {
            string chartObject=sparam;
            findPrefixObject=-1;
            //---
            for(int i=QUANT_OBJ-1;i>=0;i--)
              {
               //---  Aktionen, wenn Namen vollständig zusammenfallen:
               if(StringCompare(chartObject,nameObj[i],true)==0)
                 {
                  //--- Den Alarm deaktivieren, um die Looping bei der Entfernungsoperation zu vermeiden:
                  flagAntivandal=-1;
/*Entfernen wir Objekte, bei den die Erstellungszeit  der Erstellungszeit des gelöschten oder des geänderten 
 Objektes gleich ist:*/
                  ObDelCreateTimeExcept0(timeCreateObj[i],0,0,OBJ_EDIT);
                  //--- Entfernen wir den Indikator aus dem Chart:
                  ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
                  //---
                  ChartRedraw();
                  return;
                 }
              }//for(int i=QUANT_OBJ-1;i>=0;i--)
            return;
           }//if(findPrefixObject==0)
         return;
        }//if(flagAntivandal==0)
      return;
     }//if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)  

4.1.10. Die Funktion für die Löschung der Objekte nach ihrer Erstellungszeit ObDelCreateTimeExcept0():

Das Schema der Funktion für die Löschung der Objekte nach ihrer Erstellungszeit könnte folgendermaßen aussehen:

void ObDelCreateTimeExcept0(datetime &create_time,// die Erstellungszei
                            long chart_ID=0,// Der Identifikator des Charts 
                            int sub_window=-1,// Die Nummer des Unter-Fensters
                            ENUM_OBJECT type=-1)// -1 = Alle Objekttypen
  {
/*Verlassen der Funktion, wenn die Objektszeit = 0(1970.01.01 00:00:00) ist,
 Um die Objekte aus dem Chart nicht zu löschen, die manuell oder 
 vom Programm erstellt wurden, bei den die Erstellungszeit nach dem Neustart des Terminals auf
 0 zurückgesetzt werden konnte:*/
   if(create_time==0){return;}
   int quant_obj=0;
   quant_obj=ObjectsTotal(chart_ID,sub_window,type);
//---
   if(quant_obj>0)
     {
      datetime create_time_x=0;
      string obj_name=NULL;
      //---
      for(int i=quant_obj-1;i>=0;i--)
        {
         obj_name=ObjectName(chart_ID,i,sub_window,type);
         create_time_x=(datetime)ObjectGetInteger(chart_ID,obj_name,
                        OBJPROP_CREATETIME);
         //---
         if(create_time_x==create_time)
           {ObDelete(chart_ID,obj_name);}
        }
     }
   return;
  }
//+------------------------------------------------------------------+

Es verfügt einen inneren Filter, so dass, wenn das Erstellungsdatum des "geschützten" Objekts gleich 0 ist (es bedeutet:1970.01.01 00:00:00), dann sollte die Verarbeitung abgebrochen werden. Das ist dafür notwendig, um die Objekte aus dem Chart nicht zu löschen, die manuell oder vom Programm erstellt wurden, bei dem die Erstellungszeit nach dem Neustart des Terminals auf 0 zurückgesetzt werden konnte.

4.1.11. Die Funktion ObDelete() im Code oben:

Sie wurde aus der Bibliothek ObjectCreateAndSet genommen, und es ist bei ihr ein Fehlerausgang vorgesehen, wenn Objekte gelöscht werden:

bool ObDelete(long chart_ID,string name)
  {
   if(ObjectFind(chart_ID,name)>-1)
     {
      ResetLastError();
      if(!ObjectDelete(chart_ID,name))
        {
         Print(LINE_NUMBER,__FUNCTION__,", Error Code = ",
               GetLastError(),", name: ",name);
         return(false);
        }
     }
   return(true);
  }

4.1.12. Die Funktion für die Löschung des Indikators:

//+------------------------------------------------------------------+
//| Die Löschung des Indikators aus dem Chart                                    |
//+------------------------------------------------------------------+
void ChIndicatorDelete(const string short_name,//Der Kurzname des Indikators
                       const string &text_0,//Der Text, wenn es einen Fehler bei der Löschung des Indikators gibt
                       const string &text_1,//Der Text, wenn es erfolgreich gelöscht wurde
                       const long  chart_id=0,// Der Identifikator des Charts
                       const int   sub_window=-1// Die Nummer des Unter-Fensters
                       )
  {
   bool res=ChartIndicatorDelete(chart_id,sub_window,short_name);
//---
   if(!res){Print(LINE_NUMBER,text_0,GetLastError());}
   else Print(LINE_NUMBER,text_1);
  }
//+------------------------------------------------------------------+

wo LINE_NUMBER — das ist in der #define angegebene allgemeine Anfang des Meldungstexts, der die Zeilennummer des Codes enthält:

#define LINE_NUMBER    "Line: ",__LINE__,", "

Betrachten wir das nächste Schema.


4.2. Die "Self-recovery" (Selbstwiederherstellung) der Programmsobjekte

Erstellung der Selbstwiederherstellung ("Self-recovery") der Objekte erfordert mehr ernsthafte Aufmerksamkeit bei der Anordnung und der Änderung der Flagge Werte, damit das Programm keine Looping hätte.

Das Schema wurde basierend auf einer Änderung des vorherigen Codes test_count_click_1 beschrieben. Der vollständige Code kann praktisch eingesehen und probiert werden, Sie können es in der beigefügten Datei unter dem Namen test_count_click_2 finden.

4.2.1. Die Dateierstellung mit diesem Schema im Code:

Die Datei test_count_click_1 wird unter dem Namen test_count_click_2 gespeichert.

4.2.2. Die Variablen, die über alle Funktionen im Rahmen der Sichtbarkeit für alle Programmteile deklariert werden, das heißt, bis der Block der Funktion OnInit():

Der Name des Indikators in #define wurde für eine nachfolgende interne Substitution ersetzt:

#define NAME_INDICATOR             "count_click_2: "

Eine weitere Variable wird auch hinzugefügt, aber dieses Mal für eine adaptive Hilfsflagge, zusätzlich zu der zuvor beschriebenen einfachen Hauptflagge:

int flagAntivandal, flagResetEventDelete;

Eine Variable wird auch für den Text der Nachricht erstellt, bevor Wiederherstellungsoperationen durchgeführt werden:

string textRestoring;

4.2.3. Die Funktion LanguageTerminal(), die ist für die Texte der Nachrichten je nach der Sprache des Handelsterminals verantwortlich:

Es wurde eine Nachricht hinzugefügt, die vor den Wiederherstellungsoperationen bei unzulässiger Löschung oder Änderung der Bedienfeldsobjekte angezeigt wird:

void LanguageTerminal()
  {
   string language_t=NULL;
   language_t=TerminalInfoString(TERMINAL_LANGUAGE);
//---
   if(language_t=="Russian")
     {
      textObj[3]="Ja: ";
      textObj[4]="Nein: ";
      textObj[5]="Всего: ";
      //---
      textRestoring="Die Benachrichtigung über den Versicherungsfall: Objekt ";
      //---
      StringConcatenate(textDelInd[0],"  Der Indikator konnte nicht gelöscht werden: \"",
                        prefixObj,"\". Der Code des Fehlers: ");
      StringConcatenate(textDelInd[1]," Der Indikator wurde vom Chart gelöscht: \"",
                        prefixObj,"\".");
     }
   else
     {
      textObj[3]="Yes: ";
      textObj[4]="No: ";
      textObj[5]="All: ";
      //---
      textRestoring="Notification of the insured event: object ";
      //---
      StringConcatenate(textDelInd[0],"Failed to delete indicator: \"",
                        prefixObj,"\". Error code: ");
      StringConcatenate(textDelInd[1],
                        "Withdrew from chart indicator: \"",
                        prefixObj,"\".");
     }
//---
   return;
  }

Ich habe diesen Text in der Annahme gestellt, dass die betrachteten Varianten als Sicherung vor unerwünschten Ereignissen dienen.

4.2.4. Im Block der Funktion OnInit():

Bevor die Funktion der Objekte erstellt wird, initialisieren wir beide Flaggen mit dem Wert -1 (Der Alarm ist vollständig deaktiviert):

flagAntivandal = flagResetEventDelete = -1;

Nach dem Erstellungsblock der Bedienfeldsobjekte und der Revision des Erstellungszeitsarrays für Objekte - initialisieren wir die Flagge mit dem Wert 0 (Der "Alarm" wird aktiviert):

//--- Erstellen wir das Feld:
   PanelCreate();
/*Die Revision des Arrays von der Erstellungszeit der Objekte bis zum Arbeitsende
des Programms, wenn etwas schief geht:*/
   if(!RevisionCreateTime(QUANT_OBJ,timeCreateObj))
     {return(REASON_INITFAILED);}
/*Setzen wir die Anti-Vandalismus-Flagge in den Reaktionsszustand auf 
die Löschung und Änderung der Objekte:*/
   flagAntivandal=flagResetEventDelete=0;

4.2.5. Betrachten wir die Funktion OnChartEvent():

Wir werden den zuvor bestehenden Block der Benachrichtigungsverarbeitung über Ereignisse von Veränderungen und Löschungen der Objekte um den unten aufgeführten Block ersetzen. Im neuen Block werden die Aktionen nach den Regeln durchgeführt, die auch allgemein für die Ereignisse der Löschung und Änderung der Objekte sind:

  • Zunächst einmal überprüfen, ob der "Schutz" aktiviert ist. Wenn nicht, dann wird es aus dem Ereignisseverarbeitungsblock verlassen.
  • Dann, wenn die Hilfsflagge für eine zusätzliche Zurücksetzung der Löschungsereignisse höher ist als 0, werden die eingehenden Benachrichtigungen über Ereignisse der Löschung und Änderung der Bedienfeldsobjekte zurückgesetzt, bis die Flagge gleich 0 ist.
  • Nur wenn die Haupt und Hilfsflagge gleich Null sind, sind Wiederherstellungsmaßnahmen möglich, bei nicht autorisierten Änderungen oder Entfernungen der Objekte durchzuführen.
else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)
     {
      if(flagAntivandal==-1){return;}
      else if(flagResetEventDelete>0)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)
           {
            findPrefixObject=-1;
/*Das Zurücksetzen des Wertes von dem Flaggezähler der Ereignisse für eine nachfolgende Looping 
der Codesfunktionalität vor den Löschungsereignissen der Objekte 
wegen Wiederherstellungsmaßnahmen:*/
            flagResetEventDelete=flagResetEventDelete-1;
            //---
            return;
           }
         return;
        }
      else if(flagAntivandal==0 && flagResetEventDelete==0)
        {
         //--- Schauen wir auf das Zusammenfallen nach Präfix:
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)//wenn ein Zusammenfallen nach Präfix gibt
           {
            string chartObject=sparam;//Der Objektname im Ereignis
            findPrefixObject=-1;
/*Überprüfung, ob es ein "geschütztes" Objekt ist und wenn ja, dann  
            macht man Wiederherstellungsmaßnahmen:*/
            RestoringObjArrayAll(chartObject,prefixObj,flagAntivandal,
                                     flagResetEventDelete,QUANT_OBJ,nameObj,
                                     timeCreateObj);
            return;
           }//if(findPrefixObject==0)
         return;
        }//else if(flagAntivandal==0 && flagResetEventDelete==0)
      return;
     }//else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)

Die Hauptwiederherstellungsmaßnahmen wurden in der Funktion RestoringObjArrayAll() aufgebaut. Mehrere solcher Funktionen können gleichzeitig in dem Block für verschiedene Gruppen von Objekten angewendet werden. Sie können ein relevantes Beispiel im fünften Kapitel dieses Artikels finden. Der Objecktname nach dem Löschung- oder Änderungsereignis gehört zu dieser Funktion nach einer Überprüfung durch Präfix, wenn Präfix mit dem "geschützten" Objekte gleich sind.

4.2.6. Die Funktion RestoringObjArrayAll().

Es enthält die folgenden Maßnahmen:

  • Wenn die Überprüfung für ein vollständiges Zusammenfallen der Namen zeigt, dass das Objekt durch Ereignisse "geschützt" ist, dann:
    • die Hauptflagge des "Alarms" erhält den Wert -1 (der "Alarm" wird für die Zeit der "freundlichen" Aktionen deaktiviert);
    • Falls es ein Ereignis der Objektlöschung war, die Hilfsflagge wird auf die Gesamtmenge der "geschützten" Objekte minus eins gesetzt, weil, wenn das Löschungsereignis des Objektes verarbeitet wird, bedeutet es, dass wenigstens ein Objekt zu diesem Moment gelöscht wurde.
  • Nach diesen vorläufigen Maßnahmen werden die verbleibenden geschützten Objekte durch Präfix mit der unten gezeigten Funktion ObDeletePrefixFlag() gelöscht, gleichzeitig werden die gelöschten Objekte berechnet. Basierend auf dieser Berechnung wird der Wert der Hilfsflagge flagResetEventDelete korrigiert, falls es erforderlich ist.

Und da bei der Löschung der Objekte ein Löschungsereignis entsteht, werden sie nachfolgend nicht verarbeitet, bis der Wert der Hilfsflagge nicht auf 0 zurückgesetzt wird, da sie in diesem Teil des Codes verarbeitet werden:

else if(flagResetEventDelete>0)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)
           {
            findPrefixObject=-1;
/*Das Zurücksetzen des Wertes von dem Flaggezähler der Ereignisse für eine nachfolgende Looping 
der Codesfunktionalität vor den Löschungsereignissen der Objekte 
wegen Wiederherstellungsmaßnahmen:*/
            flagResetEventDelete=flagResetEventDelete-1;
            //---
            return;
           }
         return;
        }

    • Wenn Objekte von Präfix gelöscht werden, und die Hilfsflagge den Wert nimmt, der gleich der tatsächlichen Anzahl der "Entlassung" von nicht zur Verarbeitung erforderlichen Ereignissen ist, es wird eine Funktion für das neuzeichende Charts platziert. Erst dann werden weitere Aktionen fortgesetzt.
    • Nach dem Neuzeichen des Charts geht die Suche und Löschung der Objekte nach ihrer Erstellungszeit, die gleich der Erstellungszeit des Objektes ist, nach dem ein Ereignis gekommen ist. Falls ein Ereignis wegen der Umbenennung des Objektes entstanden ist, und am Chart erschien ein "herrenloses" Objekt. Die Löschung wird durch die bekannte Funktion punkt.4.1.10 ObDelCreateTimeExcept0() durchgeführt.
    • Die letzten Schritte der Verarbeitung: die Neuerstellung des Bedienfelds oder dessen Teil, der zur Zeit wiederhergestellt werden muss.
    • Schließlich ist das Nachzeichen des Charts und Zuweisung des Wertes 0 zur Semaphorsflagge (gesetzt auf "Alarm"). Zu diesem Zeitpunkt hat der notwendige Wert für die Hilfsflagge automatisch gebildet worden, so dass wir nichts schreiben müssen.

//+------------------------------------------------------------------+
//|Die Funktion "Self-Recovery" der Objekte für OnChartEvent()          |
//+------------------------------------------------------------------+
//|string sparam = der Objektname, der in OnChartEvent()gekommen ist         |
//|string prefix_obj = die gemeinsame Präfix der geschützten Objekte             |
//|int &flag_antivandal = die Flagge zur Aktivierung / Deaktivierung des Alarms     |
//|int &flag_reset = die Flagge des Zurücksetzens eines Ereignis                             |
//|int quant_obj = die Gesamtmenge der Objekte im "geschützten"          |
//|Array                                                           |
//|string &name[] = Das Array der geschützten Objekte                |
//|datetime &time_create[] = Das Array von Namen der "geschützten" Objekte   |
//|int quant_obj_all=-1 die Gesamtmenge der wiederhergestellten Objekte  |
//|Die Programme, >= quant_obj (wenn -1 ist, dann ist es gleich quant_obj)             |
//|const long chart_ID = 0  Der Identifikator des Charts                     |
//|const int sub_window = 0 Das Index des Fensters                              |
//|int start_pos=0 von welcher Position im Namen der Objekte beginnt die Präfix-Suche |
//+------------------------------------------------------------------+
int RestoringObjArrayAll(const string sparam,
                         const string prefix_obj,
                         int &flag_antivandal,
                         int &flag_reset,
                         const int quant_obj,
                         string &name[],
                         datetime &time_create[],
                         int quant_obj_all=-1,
                         const long chart_ID=0,
                         const int sub_window=0,
                         const int start_pos=0
                         )
  {
//--- Nehmen wir die Ergebnisse hier:
   int res=-1;
/*Die Überprüfung auf Richtigkeit der Anzahleingabe von Objekten auf externe Parameter 
   der Funktion. Die Tatsache, dass falsche externe Parameter
   dieser Funktion bei der Erstellung des Codes eingegeben wurden, 
   das wird erst nach dem Auftreten eines "gesicherten" Ergebnisses bekannt.
   Aus diesem Grund muss man im Voraus überprüfen, dass Sie richtige externe Parameter für diese Funktion einstellen,
   wenn Sie den Code erstellen.*/
   if(quant_obj<=0)//wenn die angegebene Menge der geschützten Objekte <= 0 ist
     {
      Print(LINE_NUMBER,__FUNCTION__,
            ", Error Code. Wrong value: quant_obj =",quant_obj);
      return(res);
     }
   else   if(quant_obj>quant_obj_all && quant_obj_all!=-1)
     {
      Print(LINE_NUMBER,__FUNCTION__,
            ", Error Code. Not the correct value: quant_obj_all");
      return(res);
     }
   else if(quant_obj_all==-1){quant_obj_all=quant_obj;}
//--- Die Variable für einen Vergleichswert des vollständigen Objektnamens:
   int comparison=-1;
/*Die Loop des Namensvergleichs, der nach dem Objektsereignis mit Namen in 
 Array der geschützten Objekte gekommen ist:*/
   for(int i=quant_obj-1;i>=0;i--)
     {
      comparison=StringCompare(sparam,name[i],true);
      //---  Aktionen, wenn Namen vollständig zusammenfallen:
      if(comparison==0)
        {
         comparison=-1;
         res=1;
         //--- Die Benachrichtigung über das Auftreten eines  Versicherungsfalls:
         Print(LINE_NUMBER,textRestoring,sparam);
/*Während die Programmobjekte wieder hergestellt werden, setzen wir die Flagge 
zur Reaktion auf die Löschungsereignisse der Objekte:*/
         flag_antivandal=-1;
/*Der Anfangswert der Zählerflagge der Ereignisse, die nicht mehr  
für die weitere Verarbeitung der Ereignisse benötigt werden. Um die weitere Looping in der Codefunktionalität  
vor den Löschungsereignissen 
der Objekte wegen Wiederherstellungsmaßnahmen zu vermeiden:*/
         flag_reset=quant_obj_all-1;
         //--- Löschen, wenn sie es gibt, die übrigen geschützten Objekte des Arrays:
         ObDeletePrefixFlag(flag_reset,prefix_obj,chart_ID,sub_window,start_pos);
         //--- Das Neuzeichen des Charts:
         ChartRedraw();
         //--- Löschen, wenn sie es gibt, die umbenennen Objekte:
         ObDelCreateTimeExcept0(time_create[i],chart_ID,sub_window);
         //--- Neuerstellung der Objekte:
         PanelCreate();
         //--- Das letzte Neuzeichen des Charts:
         ChartRedraw();
         //--- Aktivierung des Alarms:
         flag_antivandal=0;
         //---
         return(res);
        }
     }//for(int i=QUANT_OBJECTS-1;i>=0;i--)
   return(res);
  }
Hinweis: Die Funktion hat aus einem Grund keine Auswahl durch den Objekttyp zur Verfügung. Da während der "Selbstwiederherstellung" der Objekte hat weniger Lust, die Menge der Verarbeitung zu verringern, indem das Bereich der Verarbeitung durch den Objekttyp verringert wird, kann es zur entgegengesetzten Wirkung führen, wenn während der Wiederherstellung alle löschende und neuerstellte Bedienfeldsobjekte unterschiedlicher Typen haben können. Von daher ist aus meiner Sicht am besten, wenn die Strategie der Bereichverringerung der Verarbeitung nach einem bestimmten Objektstyp nicht angewendet wird, wenn die Bedienfeldsobjekte zum Moment des unbefugten Eingriffs auf dem Chart aus verschiedenen Typen bestehen. Und unter der Annahme, dass es möglicherweise diejenigen sein können, die diese Warnung ignorieren, wird die obige Funktion entfernt.

Sie können unerwünschte Effekte selbst sehen, wenn Sie die Auswahl nach dem Objekttyp während der "Selbstwiederherstellung" im Beispiel aus dem fünften Kapitel des Artikels schreiben und anwenden, wo Objekte von verschiedenen Typen auf dem Bedienfeld in vorhanden sind. Sie müssen nur noch Print() in den Blöcken des Codes für die Verarbeitung und Wiederherstellung der Ereignisse im Voraus eingeben.

Ich möchte noch dazu hinzufügen, dass Sie Ressourcen leicht sparen können, wenn Sie im Code durch die Reduzierung der Verarbeitungsmenge nach dem Objektstyp einstellen, es kann einfach in der obigen Variante durch "self-departure" des Programms aus dem Chart gemacht werden.

4.2.7. Die Funktion ObDeletePrefixFlag() — richtet Objekte durch Präfix zu entfernen und ggf. korrigiert den Wert der Hilfsflagge:

Hauptsächlich wurde hier das Schema des Codes verwendet, die im Buch Sergej Kovalev aufgeführt wurde, und der auch im Forum MQL4 von Artem Trishkin und dem unbekannten Benutzer 7777877 erwähnt wurde. Ich habe damals nicht genug Aufmerksamkeit darauf gegeben, weshalb bin ich dankbar, die es im Forum gebracht haben, da das Basis des Programms universell ist und hat mich in vielen verschiedenen Aufgaben unterstützt.

Grundsätzlich ist hier seine Vielfalt:

//+------------------------------------------------------------------+
//| int &flag_reset = die Flagge des Zurücksetzens eines Ereignis und Löschung der Objekte      |
//| string prefix_obj = die gemeinsame Präfix in Objektenamen              |
//| long  chart_ID = Der Identifikator des Charts                           | 
//| int   sub_window=-1 = Das Index des Fensters (-1 = alle)                     |
//| int start_pos=-1 = die Anfangsposition des Untersatzes der gemeinsamen Präfix in |
//| Objektnamen                                                   |
//+------------------------------------------------------------------+
int ObDeletePrefixFlag(int &flag_reset,
                       string prefix_obj,
                       const long chart_ID=0,
                       const int sub_window=0,
                       int start_pos=0)

  {
   int quant_obj=ObjectsTotal(chart_ID,sub_window,-1);
   if(quant_obj>0)
     {
      int count=0;
      int prefix_len=StringLen(prefix_obj);
      string find_substr=NULL,obj_name=NULL;
//---
      for(int i=quant_obj-1;i>=0;i--)
        {
         obj_name=ObjectName(chart_ID,i,sub_window,-1);
         find_substr=StringSubstr(obj_name,start_pos,prefix_len);

         if(StringCompare(find_substr,prefix_obj,true)==0)
           {
            count=count+1;
            ObDelete(chart_ID,obj_name);
           }
        }
      if(count>0 && flag_reset<count)
        {flag_reset=count;}
     }
   return(flag_reset);
  }
Die Arbeit des Codes kann entsprechend überprüft werden:
  • Starten Sie den beigefügten Testcode auf dem Chart;
  • klicken Sie auf die Objekte, die zu "Ja" und "Nein" gehören, erhöhen Sie dabei die Werte von Null auf einen anderen Wert;
  • und dann versuchen Sie, diese Bedienfeldsobjekte durch den Eigenschaftsdialog zu ändern oder zu löschen.
Nach der Ausführung der automatischen Wiederherstellungsmaßnahmen werden im Feld wieder die "geklickten" Zahlen sein, die dort zur Zeit der Änderung oder Löschung ihrer Objekte waren, da die Menge der Klicks im Datenarray gespeichert wird, das bei der Neuerstellung des Feldes verwendet wurde.

Allerdings können verschiedene Reaktionen auf verschiedene Objekte erstellt werden.

Wir haben den Hauptteil des Verfahrens dargestellt, mit Ausnahme einiger Sonderfälle, wie zum Beispiel:

  • das Verarbeitungsereignis überspringen;
  • Die Änderung der Objekte-Eigenschaften durch ein anderes Programm.

Lassen Sie uns nun auf das Beispiel einer praktischen Realisierung beider Reaktionsvariante des Programms auf die Löschung und Änderung seiner Objekte gehen.


5. Das Beispiel der Realisierung zwei Antwortsvarianten in einem Programm

Die Auswahl eines Indikators, in dem die Realisierung von zwei Möglichkeiten der Antwortsvarianten auf nicht autorisierten Aktionen Schritt um Schritt gestellt werden:

  • Wenn wir ein Beispiel einer allgemeinen Realisierung dieser Varianten auf der Grundlage eines komplexeren Codes bereitstellen, kann der Leser verwirrt werden.
  • Auch wenn die unten beigefügten Variante einfach ist, gibt es viele praktische Informationen, einschließlich auch unter "Kampf"-Bedingungen.
  • Darüber hinaus kann dieser Indikator in Arbeit mit Objekten nützlich sein, einschließlich nicht nur nach dem Thema dieses Artikels.

Und falls es in der Zukunft notwendig ist, kann es durch die Liste-Erweiterung der angezeigten Werte ergänzt werden.

Der vollständige Code wird unter dem Namen id_name_object angehängt. Ich gebe hier ein Beispiel:

  • eine Karte für die Arrays und Variable, um Objektenamen und die Karte nach Objekten zu speichern;
  • Die allgemeinen Schemas des Codes;
  • Die Abschnitte des Codes, die direkt mit dem Thema dieses Artikels verbunden sind.

Der Zweck des erwähnten Indikators: ist der, dass es beim Klick auf ein Chart des Objekts den Namen des Objekts zeigt, dessen Erstellungszeit und Typ (abgesehen von seiner eigenen). Falls es erforderlich ist, können Sie diese Werte aus den Feldern kopieren, wo sie angezeigt werden. Beim Versuch die angezeigten Werte aus dem Feld zu ändern oder zu entfernen, ist ihre Wiederherstellung vorgesehen. Dies gilt unabhängig von den Varianten, die in dem Artikel betrachtet werden, geht jedoch als Ergänzung zu ihnen.

Darüber hinaus gibt es noch die folgenden Funktionen:

  • Die "Minimierung" des Hauptteils des Felds auf dem Chart;
  • "Selbstwiederherstellung" der Objekte, wenn ein Objekt des Feldeshauptteils geändert oder gelöscht wurde;
  • "Self-departure" eines Indikators aus dem Chart, wenn die Schaltfläche des minimierten Felds gelöscht oder nach dem folgenden Prinzip geändert wurde: "wenn es minimiert wurde, dann ist es im Moment nicht sehr benötigt";
  • Die letzten beiden Maßnahmen werden unter Berücksichtigung realisiert, dass die Objekte nach einer möglichen Umbenennung aus dem Chart gelöscht werden müssen;
  • Der Titel vom Feld wird in russischer Sprache angezeigt, wenn das Terminal in Russisch ist, genauso wenn es in Englisch ist, und genauso ist es für jede andere Sprache.

Das Aussehen eines Bedienfeldes im Zusammenhang von der Sprache des Terminals

in Abb. 7. Das Aussehen eines Bedienfeldes im Zusammenhang von der Sprache des Terminals

eine Karte für die Arrays und Variable, um Objektenamen  nach Objekten zu speichern

in Abb. 8. eine Karte für die Arrays und Variable, um Objektenamen nach Objekten zu speichern


Name
Der Typ des Objektes
Wofür ist es vorgesehen
Wo wird der Text gespeichert
Schrift
Textfarbe *
Hintergrund * Farbe der Grenze*
Die Erstellungszeit wird gespeichert
nameRectLabel
OBJ_RECTANGLE_LABEL
Canvas
---
--- ---
CLR_PANEL clrNONE
timeCreateRectLabel
nameButton[0]
OBJ_BUTTON
Die Taste für die die Löschung des Indikators aus dem Chart
textButtUchar[0]**
"Wingdings"
CLR_TEXT
CLR_PANEL clrNONE
timeCreateButton[0]
nameButton[1] OBJ_BUTTON
Die Taste für die "Minimierung" des Feldes
textButtUchar[1]**
"Wingdings"
CLR_TEXT
CLR_PANEL clrNONE
timeCreateButton[1]
nameButton[2] OBJ_BUTTON
Die Taste für die "Wendung" des Feldes, nachdem es "minimalisiert" wird
textButtUchar[2]**
"Wingdings"
CLR_TEXT
CLR_PANEL clrNONE
timeCreateButton[2]
nameEdit0[0]
OBJ_EDIT
"Objekt-Name:"
textEdit0[0]
"Arial"
CLR_TEXT_BACK
CLR_PANEL CLR_BORDER
timeCreateEdit0[0]
nameEdit0[1]
OBJ_EDIT
Die Erstellungszeit:"
textEdit0[1] "Arial"
CLR_TEXT_BACK
CLR_PANEL CLR_BORDER
timeCreateEdit0[1]
nameEdit0[2]
OBJ_EDIT
Der Typ des Objektes:"
textEdit0[2] "Arial"
CLR_TEXT_BACK
CLR_PANEL CLR_BORDER
timeCreateEdit0[2]
nameEdit1[0]
OBJ_EDIT
Das Feld für die Anzeige des Objektnamens textEdit1[0]
"Arial"
CLR_TEXT
CLR_PANEL CLR_BORDER
timeCreateEdit1[0]
nameEdit1[1] OBJ_EDIT
Das Feld für die Anzeige seiner Erstellungszeit textEdit1[1] "Arial"
CLR_TEXT
CLR_PANEL CLR_BORDER
timeCreateEdit1[1]
nameEdit1[2] OBJ_EDIT
Das Feld für die Anzeige des Objekte-Typs
textEdit1[2] "Arial"
CLR_TEXT
CLR_PANEL CLR_BORDER
timeCreateEdit1[2]

 

Tabelle 2. Die Karte für Feldesobjekte

* Die Farben, die mit #define gegeben werden:

#define CLR_PANEL                  clrSilver//Der allgemeine Hintergrund des Feldes
#define CLR_TEXT                   C'39,39,39'//Die Hauptfarbe des Textes
#define CLR_TEXT_BACK              C'150,150,150' //Die Farbe des schattierten Textes 
#define CLR_BORDER                 clrLavender//Die Farbe der Rahmen

** Symbole "Wingdings":

uchar textButtUchar[3]={251,225,226};


5.1. Externe Variable:

Die Größe des Feldes wird auf der Basis der Größe einer Taste berechnet. Von daher sind die Breite und Höhe einer Taste und die Schriftgröße in den externen benutzerdefinierten Eigenschaften angezeigt. Dies ermöglicht das Feld und darin angezeigten Texte zu erhöhen, ohne Änderungen direkt im Code zu machen.

Externe benutzerdefinierte Eigenschaften eines Indikators

in Abb. 9. Externe benutzerdefinierte Eigenschaften eines Indikators


5.2. Die Variablen, die über alle Funktionen im Rahmen der Sichtbarkeit für alle Programmteile deklariert werden, das heißt, bis der Block der Funktion OnInit():

Es wurden zwei Flagge erklärt:

int flagClick, flagResetEventDelete;

flagClick — ist eine Flagge, welche die Benachrichtigungen bei Klicks auf Tasten verfolgt. Ihre Werte sind:

0
Die Verfolgung der Benachrichtigungen über Ereignisse bei Klicken der Tasten "Minimierung" des Feldes und die Löschung des Indikators aus dem Chart, das heißt, dieser Wert wird gegeben, wenn der Hauptteil des Feldes auf dem Chart ist.
-1
wird gesetzt, bevor Aktionen von "Minimierung" oder, im Gegenteil, "Maximierung" des Feldes auf dem Chart durchgeführt werden, und auch vor Aktionen der Löschung des Indikators aus dem Chart, nachdem auf die entsprechende Taste geklickt wird.
1 Bei der Verfolgung der Benachrichtigungen über Ereignisse von Maustasten auf "maximieren".

 

Weiterhin wirkt es als Haupt-"Antivandal-"Flagge im Falle der nicht autorisierten Änderung oder Entfernung der Objekte (es wurde flagAntivandal in den vorherigen Codes dieses Artikels genannt). Der Wert 0 — ermöglicht den "Alarm" des Hauptteils des Feldes zu aktivieren, 1 — die Taste "Maximierung", -1 — deaktiviert den "Alarm" während der laufenden Aktionen, falls solche Situationen auftreten.

Wenn Sie die Haupt "Antivandal-"Flagge adaptiv von Wert im Code erstellen, genauso wie Hilfsflagge für das Zurücksetzen der Verarbeitungsereignisse, dann wird eine separate Variable für diesen Zweck erforderlich.

flagResetEventDelete — ist eine Flagge, um die Verarbeitung der unnötigen Ereignisse mit adaptiven Werten zurückzusetzen, wenn die Variante "Selbstwiederherstellung" für geänderten oder gelöschten Objekte realisiert wird.

Andere Variablen, die in diesem Bereich erklärt werden, können in den beigefügten Code angezeigt werden.


5.3. Im Block der Funktion OnInit():

  • Bevor das Feld im Chart erstellt wird, erhalten Flaggen den Wert -1.
  • Das Array für Texte des Bedienfelds, in denen folglich die Werte der Chartsobjekte angezeigt werden, die angeklickt werden, sie werden erstmal mit leeren Werten gefüllt.
  • Es wird ein gemeinsames Präfix der Objekte erstellt und wird willkürlich ein kurzer Name dem Indikator zugeordnet.
  • Es werden Namen für die Feldesobjekte basiert auf der gebildeten gemeinsamen Präfix erstellt.
  • Es wird bestimmt, in welcher Sprache der Titel des Feldes abhängig von der Sprache des Terminals die Nachrichten über die Objektewiederherstellung und die zwangsweise Entfernung des Indikators sein wird.
  • Es wird eine Beschränkung auf die Breite und Höhe der Schaltfläche eingestellt, falls die externen Parameter eine falsche Größe haben.
  • Es wird das Hauptteil des Felds auf dem Chart erstellt.
  • Es wird die Revision der Arrays von der Erstellungszeit der Objekte durchgeführt.
  • Die Flaggen flagClick und flagResetEventDelete erhalten den Wert 0.
  • Dann wird versucht, die Benachrichtigung über Ereignisse einer Objektelöschung auf dem Chart zu aktivieren, wenn es in den Eigenschaften deaktiviert ist.
  • Es wird die Frequenz der Timersanschaltung in Sekunden festgelegt.

int OnInit()
  {
   flagClick=flagResetEventDelete=-1;
/*Das Array für Texte des Bedienfelds, in denen folglich die Werte der Chartsobjekte angezeigt werden, 
   die angeklickt werden:*/
   for(int i=QUANT_OBJ_EDIT-1;i>=0;i--){textEdit1[i]=" ";}
//+------------------------------------------------------------------+
/*ein Kurzname des Indikators:*/
   StringConcatenate(prefixObj,INDICATOR_NAME,"_",Symbol(),"_",
                     EnumToString(Period()));
   IndicatorSetString(INDICATOR_SHORTNAME,prefixObj);
//--- Die Erstellung der Objektnamen
   NameObjectPanel(nameRectLabel,prefixObj,"rl");
   NameObjectPanel(QUANT_OBJ_BUTTON,nameButton,prefixObj,"but");
   NameObjectPanel(QUANT_OBJ_EDIT,nameEdit0,prefixObj,"ed0");
   NameObjectPanel(QUANT_OBJ_EDIT,nameEdit1,prefixObj,"ed1");
//+------------------------------------------------------------------+
/*Die Texte des Indikators je nach der Sprache des Handelsterminals:*/
   LanguageTerminal();
//+------------------------------------------------------------------+
/*Die Einschränkungen einer Taste nach Breite und Höhe:*/
   if(objWidthHeight>=20 && objWidthHeight<=300)
     {obj0WidthHeight=objWidthHeight;}
   else if(objWidthHeight>300){obj0WidthHeight=300;}
   else {obj0WidthHeight=20;}
//--- Die Erstellung eines Bedienfelds auf dem Chart
   PanelCreate();
/*Die Revision der Arrays von der Erstellungszeit der Objekten bis zum Arbeitsende
des Programms, wenn etwas schief geht:
(Nur zwei von drei Tasten sind im Hauptteil des Feldes,
von daher ist ihre Menge bei der Revision um eine Taste weniger)*/
   if(!RevisionCreateTime(QUANT_OBJ_BUTTON-1,timeCreateButton))
     {return(REASON_INITFAILED);}
   if(!RevisionCreateTime(QUANT_OBJ_EDIT,timeCreateEdit0))
     {return(REASON_INITFAILED);}
   if(!RevisionCreateTime(QUANT_OBJ_EDIT,timeCreateEdit1))
     {return(REASON_INITFAILED);}
//---
   flagClick=flagResetEventDelete=0;
//--- Die Aktivierung der Benachrichtigungen über die Löschungsereignisse der grafischen Objekte:
   bool res;
   ChartEventObjectDeleteGet(res);
   if(res!=true)
     {ChartEventObjectDeleteSet(true);}
//--- create timer
   EventSetTimer(8);
//---
   return(INIT_SUCCEEDED);
  }

5.4. In der Funktion PanelCreate():

Feldesobjekte werden in verschiedene Namen-Gruppen unterteilt, um die Veränderung seines Aussehens in der Zukunft zu vereinfachen. Das Feld selbst wird in der oberen rechten Ecke des Charts platziert. Dementsprechend werden Abstände in Pixeln entlang der Achse X und Y die Position der linken oberen Punkte der Objekte in Bezug auf die obere rechte Ecke des Charts bestimmen.

Falls eine nicht autorisierte Umbenennung der Objekte auftritt, wird ihre Erstellungszeit bestimmt und es wird in den entsprechenden Arrays gespeichert. Für das Canvas des Feldes ist eine separate Variable vorgesehen.

void PanelCreate(const long chart_ID=0,// ID des Charts
                 const int sub_window=0)// Die Nummer des Unter-Fensters
  {
//--- Die Breite des Canvas des Feldes:
   int widthPanel=(obj0WidthHeight*11)+(CONTROLS_GAP_XY*2);
//--- Die Höhe des Canvas des Feldes:
   int heightPanel=(obj0WidthHeight*6)+(CONTROLS_GAP_XY*8);
//--- Der Abstand auf X:
   int x_dist=X_DISTANCE+widthPanel;
//---
   if(ObjectFind(chart_ID,nameRectLabel)<0)//das Canvas
     {
      RectLabelCreate(chart_ID,nameRectLabel,sub_window,x_dist,
                      Y_DISTANCE,widthPanel,heightPanel,"\n",CLR_PANEL,
                      BORDER_RAISED,CORNER_PANEL,clrNONE,STYLE_SOLID,1,
                      false,false,true);
      //--- Bestimmen und schreiben die Erstellungszeit des Objektes:
      CreateTimeGet(chart_ID,nameRectLabel,timeCreateRectLabel);
     }
//---
   x_dist=X_DISTANCE+CONTROLS_GAP_XY;
   int y_dist=Y_DISTANCE+CONTROLS_GAP_XY;
//---
   for(int i=QUANT_OBJ_BUTTON-2;i>=0;i--)
     {
      //--- Die Taste für die Minimierung und Löschung des Indikators:
      if(ObjectFind(chart_ID,nameButton[i])<0)
        {
         ButtonCreate(chart_ID,nameButton[i],sub_window,
                      x_dist+(obj0WidthHeight*(i+1)),y_dist,obj0WidthHeight,
                      obj0WidthHeight,CORNER_PANEL,
                      CharToString(textButtUchar[i]),"\n","Wingdings",
                      font_sz+1,CLR_TEXT,CLR_PANEL,clrNONE);
         //--- Bestimmen und schreiben die Erstellungszeit des Objektes:
         CreateTimeGet(chart_ID,nameButton[i],timeCreateButton[i]);
        }
     }
//---
   x_dist=X_DISTANCE+widthPanel-CONTROLS_GAP_XY;
   int y_dist_plus=(CONTROLS_GAP_XY*2)+(obj0WidthHeight*2);
//---
   for(int i=QUANT_OBJ_EDIT-1;i>=0;i--)
     {
      //--- Die Eigenschaftsnamen der Objekte:
      if(ObjectFind(chart_ID,nameEdit0[i])<0)
        {
         EditCreate(chart_ID,nameEdit0[i],sub_window,x_dist,
                    y_dist+(y_dist_plus*i),obj0WidthHeight*8,
                    obj0WidthHeight,textEdit0[i],"Arial",font_sz,
                    "\n",ALIGN_CENTER,true,CORNER_RIGHT_UPPER,
                    CLR_TEXT_BACK,CLR_PANEL,CLR_BORDER);
         //--- Bestimmen und schreiben die Erstellungszeit des Objektes:
         CreateTimeGet(chart_ID,nameEdit0[i],timeCreateEdit0[i]);
        }
     }
//---
   y_dist=Y_DISTANCE+obj0WidthHeight+(CONTROLS_GAP_XY*2);
//---
   for(int i=QUANT_OBJ_EDIT-1;i>=0;i--)
     {
      //--- Um Texte von Eigenschaftswerten der Objekte anzuzeigen:
      if(ObjectFind(chart_ID,nameEdit1[i])<0)
        {
         EditCreate(chart_ID,nameEdit1[i],sub_window,x_dist,
                    y_dist+(y_dist_plus*i),obj0WidthHeight*11,
                    obj0WidthHeight,textEdit1[i],"Arial",font_sz,
                    "\n",ALIGN_LEFT,true,CORNER_RIGHT_UPPER,
                    CLR_TEXT,CLR_PANEL,CLR_BORDER);
         //--- Bestimmen und schreiben die Erstellungszeit des Objektes:
         CreateTimeGet(chart_ID,nameEdit1[i],timeCreateEdit1[i]);
        }
     }
   return;
  }

5.5. В OnDeinit():

"Deaktivieren" der Hauptflagge für die Zeit, in der der Indikator aus dem Chart gelöscht wird, Löschung der Objekte durch Präfix, die Ereigniserzeugung aus dem Timer stoppen und die Löschung des Indikators aus dem Chart, wenn von OnInit() der Grund der Deinitialisierung REASON_INITFAILED empfangen wird:

void OnDeinit(const int reason)
  {
   flagClick=-1;
   ObjectsDeleteAll(0,prefixObj,0,-1);
   EventKillTimer();
//--- Die Löschung des Indikators, wenn es in OnInit REASON_INITFAILED ist.
   if(reason==REASON_INITFAILED)
     {
      ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
     }
//---
   ChartRedraw();
  }

5.6. В OnTimer():

Die gelegentliche Kontrollen durch die Zeit, die in OnInit() festgelegt ist, wenn die Aktivierung der Benachrichtigungen über die Löschungsereignisse der grafischen Objekte auf dem Chart in Eigenschaften an ist:

void OnTimer()
  {
//--- Die Aktivierung der Benachrichtigungen über die Löschungsereignisse der grafischen Objekte
   bool res;
   ChartEventObjectDeleteGet(res);
   if(res!=true)
     {ChartEventObjectDeleteSet(true);}
  }


5.7. Die Funktion OnChartEvent():

5.7.1. Im Block für Benachrichtigungsverarbeitung über Ereignisse der Objekte mit einem Mausklick:
Wenn die Semaphorflagge flagClick gleich 0 ist, dann:
  • Zunächst wird die Überprüfung durchgeführt, um herauszufinden, ob dies nicht ein Klick auf die Tasten des Feldeshauptteils war.
  • Wenn dies ein Klick auf die Schaltfläche Minimierung des Feldes war, dann erhält die Flagge flagClick vor den weiteren Aktionen den Wert -1.
  • Wenn eine "Minimierung" Schaltfläche geklickt wurde, dann wird das Hauptteil des Feldes minimiert und wird die Maximierung-Schaltfläche in der oberen rechten Ecke des Charts erstellt.
  • Danach erhält die Flagge flagClick den Wert von 1, was das heißt, die Klicks auf die Maximierung-Schaltfläche des Feldes und seine unbefugte Änderung oder Löschung zu verfolgen.
  • Wenn dies ein Klick auf die Schaltfläche Löschung des Indikators aus dem Chart war, dann erhält die Flagge flagClick vor den weiteren Aktionen den Wert -1. Erst dann wird versucht, den Indikator aus dem Chart zu entfernen.
  • Wenn es nicht ein Klick auf die Schaltfläche des Bedienfelds war, sondern auf ein Objekt des Charts, ausnahmsweise außer den Objekten des Indikators, dann werden im Feld die Werte des Objektes bestimmt und angezeigt: sein Name, die Erstellungszeit und der Typ.

Wenn die Semaphorflagge flagClick gleich 1ist, dann beim Klicken auf "Maximieren":

  • dann erhält die Flagge vor den weiteren Aktionen den Wert -1.
  • Die Schaltfläche wird gelöscht und es wird ein Feld erstellt.
  • Dann erhält die Flagge flagClick den Wert 0. Die Hilfsflagge flagResetEventDelete für das Zurücksetzen eines Löschungsereignis der Schaltfläche "Maximieren" erhält den Wert 1.
if(id==CHARTEVENT_OBJECT_CLICK)//id = 1
     {
      if(flagClick==0)//Wenn das Hauptteils des Bedienfelds auf dem Chart ist
        {
         string clickedChartObject=sparam;
         findPrefixObject=StringFind(clickedChartObject,prefixObj);
         //---
         if(findPrefixObject==0)
           {
            findPrefixObject=-1;
            //---
            for(int i=1;i>=0;i--)
              {
               if(StringCompare(clickedChartObject,nameButton[i],true)==0)
                 {
                  switch(i)
                    {
                     //--- Die Taste für die "Minimierung":
                     case 1:flagClick=-1;
                     MinimizeTable(nameButton,2,textButtUchar,2,
                                   timeCreateButton,obj0WidthHeight);
                     flagClick=1;return;
                     //--- Die Taste für die die Löschung des Indikators aus dem Chart:
                     case 0:flagClick=-1;
                     ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
                     return;
                     default:return;
                    }
                 }
              }
           }
         else//wenn ein Klick nicht auf die Tasten des Bedienfeldes ist
           {
            SetValuesTable(clickedChartObject);//Bestimmen den Wert des Objektes
            return;
           }
        }
      //--- Wenn ein Klick auf die Schaltfläche "Maximieren" des Feldes ist:
      else if(flagClick==1)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)
           {
            string clickedChartObject=sparam;
            findPrefixObject=-1;
            //--- Die Taste für die "Maximieren" des Feldes:
            if(StringCompare(clickedChartObject,nameButton[2],true)==0)
              {
               flagClick=-1;
               //--- Die Haupt-Aktionen beim Drücken der Taste "Maximieren" des Feldes
               ToExpandTheTable(clickedChartObject);
               //---
               flagClick=0;
               //--- Für das Zurücksetzen des Löschungsereignises dieser Schaltfläche:
               flagResetEventDelete=1;
               //---
               return;
              }
           }
         return;
        }
      return;
     }//if(id==CHARTEVENT_OBJECT_CLICK)
5.7.2. Im Block für Benachrichtigungsverarbeitung über das Korrektursende des Textes in der grafischen Objekte Edit:
Wenn die Werte der grafischen Objekte im Bereich dieses Feldes sind, werden sie für das Kopieren aus diesen Feldern zur Verfügung stehen. Deswegen, wenn vom Indikator angezeigten Werte beim Kopieren versehentlich / absichtlich geändert oder gelöscht werden, dann wird der vorherige Text wiederhergestellt:
else  if(id==CHARTEVENT_OBJECT_ENDEDIT)//id = 3
     {
      findPrefixObject=StringFind(sparam,prefixObj);
      if(findPrefixObject==0)
        {
         string endEditChartObject=sparam;
         findPrefixObject=-1;
         int comparison=-1;
         //---
         for(int i=QUANT_OBJ_EDIT-1;i>=0;i--)
           {
            if(StringCompare(endEditChartObject,nameEdit1[i],true)==0)
              {
               string textNew=ObjectGetString(0,endEditChartObject,OBJPROP_TEXT);
               comparison=StringCompare(textEdit1[i],textNew,true);
               //---
               if(comparison!=0)
                 {
                  ObSetString(0,nameEdit1[i],OBJPROP_TEXT,textEdit1[i]);
                 }
               //---
               ChartRedraw();
               return;
              }
           }//for(int i=0;i<QUANT_OBJ_EDIT;i++)
         return;
        }//if(findPrefixObject==0)
      return;
     }//if(id==CHARTEVENT_OBJECT_ENDEDIT)
5.7.3. Im Block für Benachrichtigungsverarbeitung über Ereignisse der Löschung oder Änderung der Objekte:
  • Wenn die Flagge flagClick gleich -1 ist, dann wird aus dem Ereignisseverarbeitungsblock verlassen, weil dieser Wert der Flagge bei seinen Aktionen verleihen wird.
  • Wenn die erste Prüfung abgeschlossen ist und es zeigte, dass die Hilfsflagge flagResetEventDelete für das Zurücksetzen der Ereignisse mehr als 0 ist, und das Objekt durch Ereignis bezieht sich auf die Objekte des Feldes, dann werden Ereignisse zurückgesetzt und vom Verarbeitungsblock verlassen.
  • Wenn die Flaggen flagClick und flagResetEventDelete gleich 0 sind, dann, wenn der Name des Objekts mit dem Ereignis eines "geschützten" Objektes zusammenfallen, werden Wiederherstellungsmaßnahmen für das Hauptteil des Feldes mit der bereits bekannten Funktion RestoringObjArrayAll() und ihr zugehörigen Funktionen durchgeführt.
  • Wenn die Hauptflagge flagClick bei dem Ereignis 1 ist, dann, wenn der Name des Objekts mit dem Ereignis des Schaltflächenamens "Maximieren" zusammenfallen, dann wird der Indikator aus dem Chart gelöscht.

else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)
     {
      if(flagClick==-1)return;
      else if(flagResetEventDelete>0)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         if(findPrefixObject==0)
           {
            findPrefixObject=-1;
            flagResetEventDelete=flagResetEventDelete-1;
            //---
            return;
           }
         return;
        }
      //--- Überprüfen, ob unser Objekt gelöscht/geändert wurde:
      else if(flagClick==0 && flagResetEventDelete==0)
        {
         findPrefixObject=StringFind(sparam,prefixObj);
         //---
         if(findPrefixObject==0)
           {
            string chartObject=sparam;
            findPrefixObject=-1;
            int res=-1;
            //--- Die Aktion, wenn das Objekt das Canvas des Bedienfelds ist:
            res=RestoringObjOneAll(chartObject,prefixObj,flagClick,
                                   flagResetEventDelete,nameRectLabel,
                                   timeCreateRectLabel,QUANT_OBJ_ALL);
            //---
            if(res==1){return;}
            //--- Die Aktion, wenn das Objekt die Taste des Bedienfelds ist:
            res=RestoringObjArrayAll(chartObject,prefixObj,flagClick,
                                     flagResetEventDelete,QUANT_OBJ_BUTTON,
                                     nameButton,timeCreateButton,QUANT_OBJ_ALL);
            //---
            if(res==1){return;}
            //--- Die Aktion, wenn das Objekt das Schreiben (Edit0) des Bedienfelds ist:
            res=RestoringObjArrayAll(chartObject,prefixObj,flagClick,
                                     flagResetEventDelete,QUANT_OBJ_EDIT,
                                     nameEdit0,timeCreateEdit0,QUANT_OBJ_ALL);
            //---
            if(res==1){return;}
            //--- Die Aktion, wenn das Objekt das Schreiben (Edit1) des Bedienfelds ist:
            res=RestoringObjArrayAll(chartObject,prefixObj,flagClick,
                                     flagResetEventDelete,QUANT_OBJ_EDIT,
                                     nameEdit1,timeCreateEdit1,QUANT_OBJ_ALL);
            //---
            return;
           }
        }
      else if(flagClick==1)//Wenn die Taste des minimierten Feldes geändert oder gelöscht wird
        {
         string clickedChartObject=sparam;
         if(StringCompare(clickedChartObject,nameButton[2],true)==0)
           {
            flagClick=-1;
            //--- Die Löschung des Indikators aus dem Chart:
            ChIndicatorDelete(prefixObj,textDelInd[0],textDelInd[1],0,0);
            return;
           }
         return;
        }
      return;
     }//else  if(id==CHARTEVENT_OBJECT_DELETE || id==CHARTEVENT_OBJECT_CHANGE)
Die neue Funktion in diesem Block ist die Funktion RestoringObjOneAll(), und es wird angewendet, wenn das Carnvas geändert oder gelöscht wird. Sie ist ähnlich der hier vorhandenen Funktion RestoringObjArrayAll().
//+------------------------------------------------------------------+
//|string sparam = der Objektname, der in OnChartEvent()gekommen ist         |
//|string prefix_obj = die gemeinsame Präfix der geschützten Objekte             |
//|int &flag_antivandal = die Flagge zur Aktivierung / Deaktivierung des Alarms     |
//|int &flag_reset = die Flagge des Zurücksetzens eines Ereignis                             |
//|string name = der Objektname                                         |
//|datetime time_create = Die Erstellungszeit des Objektes                     |
//|int quant_obj_all = die Gesamtmenge der wiederhergestellten Objekte   |
//|Die Programme, >= quant_obj (wenn -1 ist, dann ist es gleich quant_obj)             |
//|const long chart_ID = 0  Der Identifikator des Charts                     |
//|const int sub_window = 0 Das Index des Fensters                              |
//|int start_pos=0 von welcher Position im Namen der Objekte beginnt die Präfix-Suche    |
//+------------------------------------------------------------------+
int RestoringObjOneAll(const string sparam,
                       const string prefix_obj,
                       int &flag_antivandal,
                       int &flag_reset,
                       string name,
                       datetime time_create,
                       const int quant_obj_all,
                       const long chart_ID=0,
                       const int sub_window=0,
                       int start_pos=0
                       )
  {
   int res=-1;
   int comparison=-1;
//---
   comparison=StringCompare(sparam,name,true);
//---  Aktionen, wenn Namen vollständig zusammenfallen:
   if(comparison==0)
     {
      res=1;
      comparison=-1;
      //--- Die Benachrichtigung über das Auftreten eines  Versicherungsfalls:
      Print(LINE_NUMBER,textRestoring,sparam);
      //---
      flag_antivandal=-1;
      flag_reset=quant_obj_all-1;
      //---
      ObDeletePrefixFlag(flag_reset,prefix_obj,chart_ID,sub_window,start_pos);
      //---
      ChartRedraw();
      //---
      ObDelCreateTimeExcept0(time_create,chart_ID,sub_window,-1);
      //---
      PanelCreate();
      //---
      ChartRedraw();
      //---
      flag_antivandal=0;
      //---
      return(res);
     }
   return(res);
  }

Der vollständige Code wird unter dem Namen: id_name_objectangehängt.


6. Fazit

Wie Sie sehen können, es sind die einfachen Regelungen und ihre Variationen, die auf der Grundlage des Flaggensystems in diesem Artikel erwähnt wurden, können nach Bedarf bezüglich viele oder eines Objektes zu einem bereiten Code hinzugefügt werden. Es kann auch dabei keine Notwendigkeit bestehen, erheblichen Veränderungen in den Teilen des Codes zu machen, die im Programm für die Hauptarbeit verantwortlich sind.

Falls es erforderlich ist, kann man sich andere relevante Aktionen im Code vornehmen:

  • Die Änderung einiger Objekte des Bedienfeldes durch andere Programme, beispielsweise aufgrund der fehlerhaften Arbeit seines Codes;
  • Ereignisbenachrichtigungen überspringen, wenn sie viel sind.

Zum Beispiel können Sie einige zusätzliche Überprüfungen während der "geplanten" Aktionen auf dem Feld, sowie selektiver oder totaler Revision-Überprüfungen nach wichtigen Daten auf dem Feld durch Timer realisieren, wenn es im Hinblick zum Code gerechtfertigt ist.

Im Expert Advisor, zum Beispiel, können Sie Animation während der unautorisierten Änderungen oder Löschungen der grafischen Objekte mit oder ohne Anzeige der Nachrichten anordnen, wenn es keine wesentliche Beeinträchtigung zur Leistungsfähigkeit der Handelsaktivität führen wird.

Bei der Anzeige der Nachrichten können Sie sich zum Beispiel die Auswahlmöglichkeit vornehmen, das wird durch das Druck auf die entsprechenden Taste durchgeführt: das Programm aus dem Chart löschen oder versuchen, die beschädigten Objekte wiederherzustellen. Darüber hinaus können Sie einen Zähler zur Verfügung stellen, der die folgende Warnung in den Situationen von unzulässigen Löschungen oder Änderungen der Objekte anzeigt: Dies ist ein "XX"-e unbefugter Eingriff auf Objekte des Programms. Nach dem "XXX"-em Fall wird sich das Programm selbst aus dem Chart löschen. Hier finden Sie den möglichen Grund dieser Situation".

Auf Basis der reichen Möglichkeiten der MQL5 Programmiersprache und, natürlich, Ihrer neugierigen Geist und Wissen, können Sie nach ihrem Wunsch verschiedene Variante erstellen, indem auch solche, die nicht in diesem Artikel aufgeführt wurden.

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/1979

Verwendung von Layouts und Containern für GUI Controls: Die CBox Klasse Verwendung von Layouts und Containern für GUI Controls: Die CBox Klasse
Dieser Artikel präsentiert eine alternative Methode für die Erzeugung von GUI-Controls, basierend auf Layouts und Containern und der Verwendung eines Layoutmanagers, der CBox Klasse. Die CBox Klasse ist ein externes Control, welches als ein Container für besondere Controls in einem GUI-Panel agiert. Sie vereinfacht das Designen von grafischen Panels und in einigen Fällen reduziert sie auch den Programmieraufwand.
Die Verwendung der Behauptung (assertions) bei der Entwicklung der Programme in MQL5 Die Verwendung der Behauptung (assertions) bei der Entwicklung der Programme in MQL5
In diesem Artikel wird Behauptung (assertions) im Rahmen der Sprache MQL5 betrachtet. Es werden zwei Beispiele für die Realisierung des Behauptungsmechanismus geben, sowie allgemeine Empfehlungen für die Verwendung der Behauptungen.
Die Verwendung von Layout und Containern für GUI Controls: Die CGrid Klasse Die Verwendung von Layout und Containern für GUI Controls: Die CGrid Klasse
Dieser Artikel präsentiert eine alternative Methode für die Erzeugung eines GUI, basierend auf Layouts und Containern und der Verwendung eines Layout-Managers — die CGrid Klasse. Die CGrid Klasse ist ein externes Control, welches wie ein Container für andere Container und Controls agiert und ein Grid-Layout verwendet.
Die Arbeit mit ZIP-Archiven in MQL5 ohne Bibliotheken von Drittanbietern Die Arbeit mit ZIP-Archiven in MQL5 ohne Bibliotheken von Drittanbietern
Die Sprache MQL5 entwickelt sich weiter und es wird zu ihr ständig neue Funktionen hinzugefügt, mit Daten zu arbeiten. Schon seit einiger Zeit ist es wegen Innovationen möglich geworden, mit ZIP-Archiven regelmäßig zu arbeiten, ohne die Beteiligung von Bibliotheken DLL der Drittanbieter. Dieser Artikel beschreibt im Detail, wie das gemacht wird. Als Beispiel ist die Beschreibung der CZIP Klasse - das universelle Werkzeug für das Lesen, Erstellen und Modifizierung der ZIP-Archive.