Galerie der in MQL geschriebenen UIs - Seite 69

 

Es wurde die Möglichkeit hinzugefügt, die Farbe von Elementrahmen programmatisch zu ändern und sie mit Parameterwerten zu verknüpfen. Dies ist ein informativer und nützlicher Indikator, der hilft, das Risikoniveau der eingegebenen Werte schnell zu erkennen. Er hat sich als praktisch und übersichtlich erwiesen. Außerdem erscheinen bei Überschreitung der festgelegten Grenzwerte Warnfenster.

Ein paar Beispiele:


Morgen werden wir es mit Beispielen und Code durchgehen.

 
Beginnen wir auf einer neuen Seite.
 

Bevor wir mit dem Thema der Implementierung des gestaffelten Schutzes der Parametergrenzen und der Benutzerwarnungen fortfahren, sollten wir ein anderes Thema erwähnen, das diesem unmittelbar vorausgeht. Nämlich die Voreinstellung der Parameter.

Ich beginne mit dem Bekannten: Die meisten MQL-Programme haben Variablen der Kategorie Eingabe. Sie werden auf der globalen Ebene deklariert und sind in einem einzigen Einstellungsfenster sichtbar. Das Fenster erscheint beim Start des Programms, und darin kann der Benutzer die Anfangswerte der "externen" Variablen ändern, wenn dies erforderlich ist. Zuvor jedoch initialisiert der Benutzer die externen Variablen innerhalb des Programms. Der Punkt ist, dass die Voreinstellungen des Programms nicht universell sind, und deshalb gibt es eine Kategorie von Variablen, die bei jedem Start die Möglichkeit der Einstellung erfordern. Es ist auch bekannt, dass jeder Versuch, während der Programmausführung manuell auf externe Variablen zuzugreifen, unmöglich ist und einen Neustart erfordert. Mit einer grafischen Schnittstelle entfällt diese Notwendigkeit. Die Programmeinstellungen können zur Laufzeit geöffnet werden.

Es besteht jedoch nach wie vor die Notwendigkeit, die Programmparameter beim Start mit Anfangswerten zu versehen.

Bei einer grafischen Oberfläche macht es keinen Sinn, Variablen vom Typ Eingabe zu deklarieren , da wir das Standard-Einstellungsfenster nicht mehr benötigen , aber das Wesen bleibt dasselbe: Anstelle von Eingabevariablen müssen wir den Parametern von Steuerelementen Anfangswerte zuweisen.

Bei der Initialisierung des Programms sollten wir eine Funktion aufrufen, die unsere eigenen Fenster, nicht das Standardfenster, mit Initialwerten versieht. Optional kann dies im KIB-Konstruktor in der Phase der Schnittstellenerstellung geschehen, wenn V_CURRENT-Werte oder EIN/AUS-Zustände usw. gesetzt werden, aber jetzt ist es möglich, Elemente programmatisch zu initialisieren. Jetzt ist es möglich, die Initialisierung von Elementen im Konstruktor und im Programm zu kombinieren.

Daher benötigen wir eine spezielle Funktion, die von OnInit() aufgerufen wird, um diese Aufgabe zu erledigen.

Was genau diese Funktion macht:

  • Öffnen der benötigten Fenster beim Start des Programms.
  • Setzen von Werten in den Zielsteuerelementen.

Wie soll die Funktion heißen?

Ich würde sie Initialize() nennen, aber jeder kann sich seine eigene Variante ausdenken.

DieHauptsache ist, dass diese Funktion in jeder Schnittstelle Expert Advisor sein muss. Sie kann mit der Funktion OnTick() eines Expert Advisors oder OnCalculate() eines Indikators verglichen werden. Es ist wichtig, dies zu verstehen.


Welchen Wert wird die Funktion zurückgeben?

Die Funktion hat den Typ void. Es besteht keine Notwendigkeit, einen Wert zurückzugeben. Wenn sie aufgerufen wird, öffnet sie die notwendigen Fenster, initialisiert die Parameter der Elemente und stellt möglicherweise einige Eigenschaften ein. Das ist im Grunde alles. Theoretisch kann man darin auch anfängliche Parametergrenzen setzen, aber ich denke, dass die Wertkontrolle in einer separaten Funktion implementiert werden wird, die bei Elementereignissen aus der API-Datei und dem Timer aufgerufen wird. Ich werde wahrscheinlich in der nächsten Version einen Ausdruck der Kontrollaufrufe schreiben.

*Es ist wichtig zuberücksichtigen, dass sich das Konzept der Schnittstelle Expert Advisors im Moment noch im Aufbau befindet und viele Entdeckungen noch vor uns liegen.


Hier ist ein Beispiel für die Initialisierungsfunktion eines Interface Expert Advisors im Rahmen des aktuellen Demoprojekts:

1. Funktionsaufruf:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int _OnInit()
  {
   //------------------------------------------------
   //Initializing program interface:
   //------------------------------------------------
   Initialize();
   //------------------------------------------------


2. Funktionsimplementierung:

void Initialize()   
{
   //------------------------------------------------
   //Opening the windows:
   //------------------------------------------------
   //1. "Main Parameters". 

    w_14_Main_Parameters();
   //------------------------------------------------

   //------------------------------------------------
   //2. "Input parameters".

   w_10_Input_parameters();
   //------------------------------------------------

   //------------------------------------------------
   //3. "Setting example 1"

   w_6_Settings_example_1();
   //------------------------------------------------


  //------------------------------------------------
  //Initializing the elements:
  //------------------------------------------------
  
   w6_d_p5_S_EDIT_Spin_the_value(55);

   w6_i_p3_H_SLIDER_Roll_the_value(55);

   w14_i_p3_V_SLIDER_Vertical_slider(55);

   w14_s_p4_EDIT_Max("100");

   w14_s_p4_EDIT_Min("0");

   w14_s_p4_EDIT_Selected("55");

   w15_i_p2_P_BAR_P1(55);

   w15_s_p4_VALUE_V1("55");
  //------------------------------------------------
}


Bis jetzt sehe ich die Struktur der Funktion wie folgt. Eine sehr einfache Funktion. Sie öffnet Fenster und sendet die gewünschten Werte an die Elementparameter. Die Initialisierung von Elementen und das Öffnen von Fenstern kann man an einigen Stellen ändern, denn beim Öffnen von Fenstern werden sofort die gewünschten Werte der Elemente angezeigt, ohne dass ein zusätzliches Redrawing nötig ist. Dies sind jedoch Kleinigkeiten.


Kommen wir nun zum Hauptthema: der Implementierung des schrittweisen Schutzes von Parametern.

 

14.Realisierung des Stufenschutzes von Parametergrenzen:

  • 1. Schreiben einer Logik zur Kontrolle der Einstellungen in den voreingestellten Grenzen und Schaffung eines Warnsystems.
  • 2. Dieerste Warnung: Der Benutzer erhält ein Signal in Form einer Änderung der Farbe von Teilen der Elemente, die für die Einstellungen verantwortlich sind.(Wir werden die Farbe von Text, Sockeln, Rahmen undSchiebebalken mit den Wertgrenzen verknüpfen).
  • 3. Zweite Warnung: Es öffnet sich ein Dialogfeld mit einem Risikohinweis und dem Vorschlag, zu den ursprünglichen Einstellungen zurückzukehren.(Testen wir die tatsächliche Möglichkeit, zu den vorherigen Einstellungen zurückzukehren, wenn wir auf die Schaltfläche "Abbrechen" klicken).
  • 4. dritte Warnung: Öffnung eines Warnfensters, das weitere Änderungen der Einstellungen blockiert und eine manuelle Bestätigung durch den Benutzer erfordert.(Prüfen wir die Blockierung von Fenstern und Elementen, wenn das Warnfenster erscheint).

//------------------------------------------------------------------------------------------------------------

Schreiben der Logik zur Kontrolle der Einstellungen innerhalb der vorgegebenen Grenzen und Erstellen eines Warnsystems:

  • Der erste Teil der Implementierung besteht darin, die Anfangswerte der Parameter der ausgewählten Elemente festzulegen und die erforderlichen Fenster zu öffnen. Zu diesem Zweck wird die Funktion Initialise() geschrieben und ihr Aufruf in die Funktion _OnInit() eingefügt.
  • Der zweite Teil der Implementierung - öffnen wir die API-Datei und schreiben wir die Verbindung der Elemente. Für jedes Element in der gemeinsamen Kette werden wir Aufrufe schreiben und den Wert an die anderen Zielelemente übergeben. Zum Beispiel: bei dem Ereignis des Feldes mit den Schaltflächen rufen wir den horizontalen Schieberegler auf und übergeben ihm den Wert. Dann, wenn das Ereignis im Fall des Schiebereglers eintritt, übergeben wir ihn zurück an das Feld mit den Schaltflächen und zusätzlich an den vertikalen Schieberegler. Letzterer wiederum übergibt den Wert an die Eingabefelder in seiner Nähe und an das Fortschrittsbalkenfenster..... Insgesamt gibt es sieben Hauptelemente in der Kette, die den Wert in mehrere Richtungen weitergeben. Hier sind sie:"Einstellungsbeispiel 1" mit den Elementen"Wert drehen" und"Wert rollen","Hauptparameter" mit den Elementen"V_SLIDER", Feld"Ausgewählt" und"Prozent", und"Verarbeitung der Daten..." mit den Elementen WERT und P_BAR .
  • Dritter Teil: Testen Sie die Verbindung.
  • Vierter Teil: Schreiben wir eine Funktion mit Parametern control mit einem bedingten Namen: void Risk_management_group_1(). Ihre Aufgabe ist es, den Benutzer über die Annäherung an die Grenzen gefährlicher Werte innerhalb dieser Gruppe von Elementen zu informieren und zu warnen, wenn die zulässigen Grenzen überschritten werden. Die Funktion akzeptiert Werte von verwandten Elementen und leitet sie durch die eingestellten Filter innerhalb der Bedingungen. Wir werden die Warnung durch entsprechende Risikostufen von Text- und Rahmenfarbänderungen umsetzen und an alle Elemente der Kette senden. Parallel dazu werden wir blockierende Fenster aufrufen, die es dem Benutzer nicht erlauben, die Aktion ohne zusätzliche Bestätigung fortzusetzen.
  • Fünfter Teil: Testen wir die Arbeit der Funktion.

//-----------------------------------------------------------------------------

Fahren wir fort:

1. setzen Sie die Anfangswerte der Parameter der ausgewählten Elemente und öffnen Sie die erforderlichen Fenster. Zu diesem Zweck schreiben wir die FunktionInitialise() und rufen sie in der Funktion _OnInit() auf.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int _OnInit()
  {
   //------------------------------------------------
   //Initializing program interface:
   //------------------------------------------------
   Initialize();
   //------------------------------------------------
void Initialize()   
{
   //------------------------------------------------
   //Opening the windows:
   //------------------------------------------------
   //1. "Main Parameters". 
    w_14_Main_Parameters();

   //2. "Input parameters".
   w_10_Input_parameters();

   //3. "Setting example 1"
   w_6_Settings_example_1();

   //------------------------------------------------
  //Initializing the elements:
  //------------------------------------------------
   w6_d_p5_S_EDIT_Spin_the_value(55);
   w6_i_p3_H_SLIDER_Roll_the_value(55);
   w14_i_p3_V_SLIDER_Vertical_slider(55);
   w14_s_p4_EDIT_Max("100");
   w14_s_p4_EDIT_Min("0");
   w14_s_p4_EDIT_Selected("55");
   w15_i_p2_P_BAR_P1(55);
   w15_s_p4_VALUE_V1("55");
  //------------------------------------------------
}

Ergebnis: Die erforderlichen Fenster werden geöffnet und die Anfangswerte für die Zielelemente werden gesetzt.


2. öffnen Sie die API-Datei und schreiben Sie die Verbindung der Elemente.Schreiben Sie für jedes Element Aufrufe und übergeben Sie den Wert an die anderen Zielelemente in der Kette:

case Settings_example_1___Spin_the_value:
  
               //------------------------------------------------------------------------------------------------------
               //What to do when the value is set?
               //------------------------------------------------------------------------------------------------------
               //Min value:  NOT SET  |   Max value:  NOT SET  |   V_step:  1.7  |   Default value:  468.99  |  Digits: 3
               //------------------------------------------------------------------------------------------------------
               w6_i_p3_H_SLIDER_Roll_the_value((int)value);

               //------------------------------------------------------------------------------------------------------
               //Your comment:
               //------------------------------------------------------------------------------------------------------
               break;
case Settings_example_1___Roll_the_value:
  
               //------------------------------------------------------------------------------------------------------
               //What to do when the slider's handle is moved?
               //------------------------------------------------------------------------------------------------------
               //Min value:  0  |   Max value:  100  |   V_step:  1  |   Default value:  55  |  Digits: Integer value
               //------------------------------------------------------------------------------------------------------
               //Transferring the value:
               w14_i_p3_V_SLIDER_Vertical_slider((int)value);

               w6_d_p5_S_EDIT_Spin_the_value((double)value);
               //------------------------------------------------------------------------------------------------------
               //Your comment:
               //------------------------------------------------------------------------------------------------------
               break;
case Main_Parameters___Vertical_slider:
  
               //------------------------------------------------------------------------------------------------------
               //What to do when the slider's handle is moved?
               //------------------------------------------------------------------------------------------------------
               //Min value:  0  |   Max value:  100  |   V_step:  1  |   Default value:  50  |  Digits: Integer value
               //------------------------------------------------------------------------------------------------------
               {
                //----------------------------------------------------- 
                //Transferring value to other destinations:
                //----------------------------------------------------- 
                w14_s_p4_EDIT_Percent(value);
                //-----------------------------------------------------
                w14_s_p4_EDIT_Selected(value);
                //-----------------------------------------------------
                w15_i_p2_P_BAR_P1((int)value);
                //-----------------------------------------------------
                w15_s_p4_VALUE_V1(value);
                //-----------------------------------------------------
                w6_i_p3_H_SLIDER_Roll_the_value((int)value);
                //-----------------------------------------------------
                w6_d_p5_S_EDIT_Spin_the_value((double)value);
                //-----------------------------------------------------
                w8_s_p4_CELL_Account_balance__Value(value);
                //------------------------------------------------------------------------------------------------------
                //Your comment:
                //------------------------------------------------------------------------------------------------------
               }
               break;


3. Testen Sie die Verbindung:

Ergebnis: Die Elementwerte sind wie vorgesehen verbunden.



4. Schreiben Sie eine Funktion zur Steuerung der Parameter unserer Gruppe von Elementen: void Risk_management_group_1().

void Risk_management_group_1(string value)
{
 uint Color = 0;
 //--------------------
 static uint This_color;
 static bool User_warned, Last_warning;
 //------------------------------------------------------------
 //Setting limit colors:
 //------------------------------------------------------------
 if((int)value < 25)                      Color = clrLightGreen;
 //------------------------------------------------------------
 if((int)value >= 25 && (int)value < 50)  Color = clrLimeGreen;
 //------------------------------------------------------------
 if((int)value >= 50 && (int)value < 70)  Color = clrGreen;
 //------------------------------------------------------------
 if((int)value >= 70 && (int)value < 85)  Color = clrDarkGreen;
 //------------------------------------------------------------
 if((int)value >= 85 && (int)value < 90)  Color = clrBrown;
 //------------------------------------------------------------
 if((int)value >= 90 && (int)value < 95)  Color = C'170,0,0';
 //------------------------------------------------------------
 if((int)value >= 95 && (int)value <=100) Color = clrRed;
 //------------------------------------------------------------  

 //------------------------------------------------------------ 
 //Changing colors when the limits are passed:
 //------------------------------------------------------------
 if(This_color != Color)
   {
    w14_s_p4_EDIT_Percent((string)Color, p4_COLOR_base); 
    //-----------------------------------------------------
    w14_s_p4_EDIT_Selected((string)Color, p4_COLOR_base); 
    //-----------------------------------------------------
    w15_i_p2_P_BAR_P1(Color, p2_COLOR_bar);
    w15_i_p2_P_BAR_P1(Color, p2_COLOR_frame);
    w15_s_p4_VALUE_V1((string)Color, p4_COLOR_frame);
                   
    w8_s_p4_CELL_Account_balance__Value((string)Color, p4_COLOR_text);
    w8_s_p4_CELL_Account_balance__Value((string)Color, p4_COLOR_frame);
    //-----------------------------------------------------
    w14_i_p3_V_SLIDER_Vertical_slider(Color,p3_COLOR_bar);
    //-----------------------------------------------------
    w15_s_p4_VALUE_V1((string)Color, p4_COLOR_text);
    //-----------------------------------------------------
    w6_i_p3_H_SLIDER_Roll_the_value(Color,p3_COLOR_bar);
    //-----------------------------------------------------
    w6_d_p5_S_EDIT_Spin_the_value((double)Color, p5_COLOR_text);
    //-----------------------------------------------------
    w6_d_p5_S_EDIT_Spin_the_value((double)Color, p5_COLOR_frame);
    //-----------------------------------------------------
    w14_i_p1_BUTTON_BUY_OFF(Color, p1_N_COLOR_frame);
    w14_i_p1_BUTTON_BUY_OFF(Color, p1_A_COLOR_frame);
    //-----------------------------------------------------
    w14_i_p1_BUTTON_SELL_OFF(Color, p1_N_COLOR_frame);
    w14_i_p1_BUTTON_SELL_OFF(Color, p1_A_COLOR_frame);
    //-----------------------------------------------------
    w7_s_p4_EDIT_Comment_1(Color, p4_COLOR_frame);
    //-----------------------------------------------------
    This_color = Color;
    //-----------------------------------------------------
   }   
 //-----------------------------------------------------
 //Opening warning window 1:
 //-----------------------------------------------------
 if((int)value >= 85 && (int)value < 95 && !User_warned)
   { 
    //---------------------------------
    //Opening dialog window:
    //---------------------------------
    w_13_Risky_managment(); 
    //---------------------------------
    //Setting flag of warning 1:
    //---------------------------------
    User_warned = true;
    //---------------------------------
   }
 //-----------------------------------------------------
 if((int)value < 85)User_warned = false;
 //-----------------------------------------------------
 //Opening warning window 2:
 //-----------------------------------------------------
 if((int)value >= 96 && !Last_warning)
   { 
    //---------------------------------
    //Calling blocking window:
    //---------------------------------
    w_17_Last_warning();
    //---------------------------------
    //Setting flag of warning 2:
    //---------------------------------
    Last_warning = true;
    //---------------------------------
   }
 //-----------------------------------------------------
 if((int)value < 95)Last_warning = false;                
 //-----------------------------------------------------                 
}

Rufen Sie die Funktion Risk_management_group_1() über die Funktion _OnInit() auf:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int _OnInit()
  {
   //------------------------------------------------
   //Initializing program interface:
   //------------------------------------------------
   Initialize();
   //----------------------------------------------------------
   //Checking default value of the parameters in the group:  
   //----------------------------------------------------------
   Risk_management_group_1();
   //----------------------------------------------------------
 

Ergebnis: funktioniert wie vorgesehen, aber bei der Eingabe eines Wertes in das Eingabefeld setzt das Warnfenster den eingegebenen Wert nicht zurück, wenn es erscheint(muss verbessert werden).

(*Auch - die Einstellung der Rahmenfarbe wurde im Update hinzugefügt, fehlt aber in der aktuellen Version).


 

Die nächste Aufgabe besteht darin, die eingegebenen Parameter durch Drücken der Schaltfläche "Abbrechen" zu löschen.

Dies ist eine sehr schwierige Aufgabe, aber ich habe sie bereits teilweise umgesetzt. Ich werde versuchen, die frühere Funktionalität wiederherzustellen.

 
Zusätzlich zur Farbanzeige implementiere ich jetzt das Blinken von Rahmen, Texten und Sockeln. Ich denke, das wird morgen fertig sein. Als nächstes werden die eingegebenen Werte mit der Schaltfläche Abbrechen gelöscht.

Das Problem ist, dass bei der Eingabe von Werten in Elemente, diese sofort vom Kernel empfangen und an die API-Datei weitergegeben werden, was logischerweise die Verarbeitung von benutzerdefiniertem Code verursacht. Es ist notwendig, die Annahme von Werten in Fenstern mit Bestätigungsschaltflächen zu verzögern, bevor sie in Parametern ankommen, und dies mit einem Klick auf "Ok" oder "Bestätigen" (oder "Übernehmen") zu verbinden.

Aber es ist auch notwendig, den Elementen die vorherigen Werte vor den Änderungen zurückzugeben, wenn der Benutzer auf die Abbruchschaltfläche (Cancel) klickt.

Dies ist ein sehr interessantes Problem, dessen Lösung die praktische Nützlichkeit der Schnittstelle sofort auf ein neues Niveau hebt. Glücklicherweise wurde das Ziel zum größten Teil schon vor langer Zeit erreicht. Es ist einfach erstaunlich, wie viele interessante Dinge bereits vor 4 Jahren implementiert wurden.

Ich denke, ich werde die Aufgabe in einer Woche bewältigen und mich dann ernsthaft mit Tabellen beschäftigen.
 

In der letzten Aufschlüsselung habe ich gezeigt, wie die farbliche Anzeige von Risiken und das Öffnen von Sperrfenstern bei der Überschreitung von festgelegten Parametergrenzen funktioniert. Es wurden jedoch zwei Probleme entdeckt, die ich nicht erwartet hatte.

1. Die Risikomanagementfunktion öffnet das erste Warnfenster, wenn ein gefährliches Niveau überschritten wird, aber wenn Sie den Cursor in diesem Moment auf dem Element gedrückt halten, wächst der Wert weiter und erreicht das nächste bedingte Niveau. - Kritisch.

2. Beim Überschreiten des kritischen Wertes öffnet sich das letzte Warnfenster, aber auch dieses stoppt die Veränderung des Wertes nicht, wenn der Benutzer die linke Maustaste weiterhin gedrückt hält.

(3) Wenn der Benutzer die Maustaste loslässt und die Warnfenster schließen möchte, kann er dies nicht tun. Um genau zu sein, kann er es nicht. Der Grund dafür ist, dass die beiden blockierenden Fenster beginnen, sich gegenseitig zu blockieren. Wenn eines der blockierenden Fenster geöffnet ist, lässt es sich leicht schließen, aber wenn zwei Fenster gleichzeitig geöffnet sind, kann nichts anderes auf der Benutzeroberfläche funktionieren. Das Programm fällt in einen Stupor, obwohl es noch funktioniert.

Das folgende Bild zeigt, wie das passiert ist:

 

Dann habe ich die Probleme mit der gegenseitigen Verriegelung der Einstellungsfenster behoben, und jetzt stören sich die Fenster nicht mehr gegenseitig. Sie führen die Sperrfunktion gemeinsam aus, ohne sich gegenseitig zu behindern.


Jetzt muss ich dafür sorgen, dass das Warnfenster automatisch Änderungen am Parameterwert stoppt, auch wenn die linke Maustaste gedrückt wird und das Element aktiv ist.

 
Heute werde ich eine Fortsetzung des Themas der farblichen Kennzeichnung von Parameterwerten - Blinken von Elementen - veröffentlichen. Die Aufgabe stellte sich als etwas komplizierter heraus, als ich dachte, also habe ich sie hinausgezögert. Am Ende hat die Lösung die aufgewendete Zeit gerechtfertigt. Jedenfalls meiner Meinung nach.