English Русский 中文 Español 日本語 Português
preview
Erstellen eines Administrator-Panels für den Handel in MQL5 (Teil III): Erweiterung der installierten Klassen für die Theme-Verwaltung (II)

Erstellen eines Administrator-Panels für den Handel in MQL5 (Teil III): Erweiterung der installierten Klassen für die Theme-Verwaltung (II)

MetaTrader 5Beispiele |
173 0
Clemence Benjamin
Clemence Benjamin

Inhalt:


Einführung

Es ist möglich, Bibliotheksklassen für MQL5 zu ändern und neue zu erstellen. Da die eingebauten Bibliotheken jedoch von der Plattform gemeinsam genutzt werden, können alle Änderungen, die wir an diesen Dateien vornehmen, entweder zu positiven Verbesserungen oder zu negativen Auswirkungen auf die aktuellen Plattformfunktionen führen. In unserem letzten Artikel haben wir kurz besprochen, wie wir die Farbe der Root-Dialogklasse bearbeitet haben, um das Aussehen unseres Panels zu beeinflussen. Unsere Schaltfläche zum Umschalten des Farbmodus oder engl. Themes änderte zwar erfolgreich die Textfarbe, nicht aber das Erscheinungsbild des Panels oder die Hintergrundfarbe der Schaltfläche.

Durch Forschung haben wir schließlich Methoden gefunden, um Theme-Verändernde Funktionalitäten sicher in die verfügbaren Klassen zu integrieren. Nach der erfolgreichen Implementierung dieser Änderungen haben wir den Algorithmus des Admin Panels an die neu integrierten Funktionen angepasst.

Neues Panel-Theme

Erfolgreicher Theme-Wechsel

Die heutige Diskussion konzentriert sich auf den Prozess, den wir unternommen haben, um das visuell ansprechende Panel auf der rechten Seite zu erhalten. Die gezeigten Theme-Farben basieren auf meiner Einstellung zur Farbauswahl während der Entwicklung; sie können im Code optimiert werden, um anderen Nutzerpräferenzen zu entsprechen, sodass Sie mit verschiedenen Farben experimentieren können, um herauszufinden, was Ihnen gefällt. Es ist wichtig, die Schlüsselkomponenten unseres Programms hervorzuheben, die zur Gesamtfunktionalität des Panels beitragen.

Ich werde sie auflisten:

  • Textfarbe
  • Oberflächenfarbe der Schaltfläche
  • Ränder
  • Hintergrundfarbe

Das sind im Wesentlichen die sichtbarsten Merkmale unseres Programms. Wenn wir eine Änderung des Themes auslösen, muss jede Komponente reagieren, indem sie ihre Anzeigeeigenschaften ändert, um die gewünschten, im Code definierten Farben zu zeigen. Am Ende dieser Diskussion möchten wir Sie mit den Fähigkeiten ausstatten, die Sie benötigen, um die verfügbaren Klassen bei der Arbeit mit Schnittstellen zu ändern und zu erweitern, wie in diesem Projekt demonstriert. 

Verstehen von Klassen in MQL5.

Um sicherzustellen, dass sowohl Experten als auch Neulinge folgen können, möchte ich alle zunächst mit dem Konzept der Klassen vertraut machen, wie es in MQL5 verwendet wird. Im Folgenden finden Sie die Definitionen und Schlüsselkonzepte, die uns helfen, die Funktionsweise von Klassen in dieser Programmierumgebung zu verstehen.

Klassen: 

Klassen sind die Grundlage der objektorientierten Programmierung (OOP) in MQL5. Sie ermöglichen es Entwicklern, verwandte Variablen (Attribute) und Funktionen (Methoden) in einer einzigen Einheit zusammenzufassen, um komplexe Konzepte und Verhaltensweisen in einem Programm darzustellen.

Aufteilung einer Klasse in zwei Klassen:

  1. Attribute: Variablen, die den Zustand oder die Daten von Objekten der Klasse speichern.
  2. Methoden: Funktionen, die das Verhalten oder die Aktionen für Objekte der Klasse definieren

Überblick über die wichtigsten Merkmale einer Klasse:

  • Bei der Kapselung in einer Klasse werden Daten (Variablen) und Methoden (Funktionen), die mit diesen Daten arbeiten, gebündelt, sodass sie vor externem Zugriff und Missbrauch geschützt sind.
  • Die Vererbung ermöglicht es einer Klasse, Eigenschaften und Methoden von einer anderen Klasse zu erben, wodurch die Wiederverwendung von Code gefördert und eine hierarchische Struktur geschaffen wird.
  • Polymorphismus ermöglicht die Überschreibung von Methoden, sodass Unterklassen spezifische Implementierungen für Methoden bereitstellen können, die bereits in ihren Elternklassen definiert sind.
  • Die Abstraktion vereinfacht die Modellierung komplexer Systeme, indem sie sich nur auf die relevanten Daten und Methoden konzentriert und unnötige Details vor dem Nutzer verbirgt.
Um auf die MetaQuotes-Header-Dateien zuzugreifen, die die für unser Projekt nützlichen GUI-Klassen enthalten, sehen Sie sich das folgende Bild an, das veranschaulicht, wie wir diese Dateien finden können.

Auffinden von MQ-Header-Dateien

Auffinden der MQL5-Header-Dateien


Ich habe einen typischen MQL5-Klassenquelltext verwendet, um uns zu helfen, die Klassen und ihre Strukturen aus einem praktischen Blickwinkel heraus zu verstehen. Siehe den Codeausschnitt unten, und ich habe den Aufbau direkt darunter in Tabellenform erklärt.

//Basic parts of a class.

class CDialog : public CWndContainer
{
public:
   // Constructor and Destructor (Methods)
   CDialog(void);   // Constructor
   ~CDialog(void);  // Destructor

   // Public Methods (Functions)
   virtual bool Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2);
   virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
   string Caption(void) const;
   bool Caption(const string text);
   bool Add(CWnd *control);   // Add control by pointer
   bool Add(CWnd &control);   // Add control by reference
   virtual bool Save(const int file_handle);
   virtual bool Load(const int file_handle);
   void UpdateThemeColors(bool darkTheme);

protected:
   // Attributes (Variables)
   bool m_panel_flag;        // Panel visibility flag
   bool m_minimized;         // Minimized state flag
   CWnd m_caption;           // Caption control
   CWnd m_client_area;       // Client area control
   CRect m_norm_rect;        // Normal (non-minimized) rectangle
   CRect m_min_rect;         // Minimized rectangle
   CWnd m_white_border;      // White border control

   // Protected Methods (Internal functions)
   virtual bool CreateWhiteBorder(void);
   virtual bool CreateBackground(void);
   virtual bool CreateCaption(void);
   virtual bool CreateButtonClose(void);
   virtual bool CreateClientArea(void);
   virtual void OnClickCaption(void);
   virtual void OnClickButtonClose(void);
   virtual bool OnDialogDragStart(void);
   virtual bool OnDialogDragProcess(void);
   virtual bool OnDialogDragEnd(void);
};

Diese Tabelle ist eine Zusammenfassung der Attribute, die in den obigen Codeschnipseln verfügbar sind, und ihrer Beschreibung.

Attribute (Eigenschaften) Beschreibung
bool m_panel_flag;

 Flag, das anzeigt, ob das Panel sichtbar ist.
bool m_minimized;

 Flag, das anzeigt, ob der Dialog minimiert ist
CWnd m_caption;

Steuerung für den Beschriftungstext.
CWnd m_client_area;

Steuerung für den Client-Bereich, in dem sich andere Elemente befinden.
CRect m_norm_rect;

Koordinaten für den normalen (nicht-minimierten) Zustand.
CRect m_min_rect;

Koordinaten für den minimierten Zustand.
CWnd m_white_border;

Steuerung für den weißen Rahmen um das Dialogfeld.

In dieser Tabelle sind die im Code der Beispielklasse verwendeten Methoden zusammengefasst.

 Methoden Beschreibung
CDialog(void)
Konstruktor, der den Dialog initialisiert.
~CDialog(void)
Destruktor zum Aufräumen von Ressourcen.
Create(...)

Erzeugt das Dialogfenster und seine Steuerelemente.
 
OnEvent(...)

  Behandelt Chartereignisse für den Dialog.
Caption(void)

Gibt den aktuellen Beschriftungstext zurück.
Caption(const string text)

Legt den Beschriftungstext fest.
Add(CWnd *control)

Fügt dem Client-Bereich ein Steuerelement per Zeiger hinzu.
Add(CWnd &control)

Fügt dem Client-Bereich ein Steuerelement per Referenz hinzu.
Save(const int file_handle)

Speichert den Zustand des Dialogs in einer Datei.
Load(const int file_handle)

Lädt den Dialogstatus aus einer Datei.
UpdateThemeColors(bool darkTheme)

Aktualisiert die Farben des Themes (dunkel oder hell).
CreateWhiteBorder(void)
Erzeugt den weißen Rahmen für den Dialog.
 
CreateBackground(void)
   Erzeugt den Hintergrund des Dialogs.
 
CreateCaption(void)

   Erzeugt den Beschriftungsbereich.
 
CreateButtonClose(void)
 Erzeugt die Schaltfläche zum Schließen.   
 
CreateClientArea(void)

  Erzeugt den Client-Bereich.
 
OnClickCaption(void)
   Behandelt das Klickereignis auf der Beschriftung.
 
OnClickButtonClose(void)

   Behandelt das Klickereignis Schließen.
 
OnDialogDragStart(void)

   Behandelt den Beginn eines Dialog-Zieh-Ereignisses.
 
OnDialogDragProcess(void)

  Behandelt das Ende eines Dialog-Zieh-Ereignisses
 
OnDialogDragEnd(void)
   Behandelt das Ende eines Dialog-Zieh-Ereignisses.

Schauen wir uns im Folgenden kurz eine der prominenten Klassen an, die wir in unserem Programm verwenden. 


Hinzufügen von Methoden für die Theme-Verwaltung zu (CDialog, CEdit und CButton)

Ich glaube, wir haben jetzt ein klareres Verständnis für die Methoden, die wir einsetzen müssen, um unser Ziel des Theme-Wechsels zu erreichen. Die Dialogbibliothek enthält bereits die wesentlichen Funktionen, die erforderlich sind, und unser nächster Schritt wird darin bestehen, die erforderlichen Methoden einzubauen.


Die Methode CDialog für die Theme-Verwaltung:


CDialog:

Die CDialog-Klasse in MQL5 ist für die Erstellung und Verwaltung von nutzerdefinierten grafischen Dialogfenstern oder Panels innerhalb der MetaTrader 5-Plattform verantwortlich. Es ermöglicht Entwicklern, Dialogfelder zu erstellen, die UI-Komponenten wie Beschriftungen, Client-Bereiche, Rahmen und Schließen-Schaltflächen enthalten. Die Klasse verarbeitet Nutzerinteraktionen wie das Klicken und Ziehen des Dialogs sowie die dynamische Aktualisierung seines Themes (z. B. das Umschalten zwischen dunklem und hellem Farbmodus). Darüber hinaus bietet es Methoden zum Speichern und Laden des Status des Dialogs, um sicherzustellen, dass seine Größe, Position und der Minimierungsstatus erhalten bleiben. Dem Dialog können Steuerelemente wie Schaltflächen und Textfelder hinzugefügt werden, was ihn zu einem vielseitigen Werkzeug für den Aufbau interaktiver und visuell ansprechender Schnittstellen in Handelsanwendungen macht.

In der Klasse CDialog haben wir eine Methode zur Handhabung dynamischer Theme-aktualisierungen eingeführt. Diese Methode ist für die Aktualisierung des visuellen Erscheinungsbildes des Dialogs verantwortlich, je nachdem, ob darkTheme aktiv ist oder nicht. Im Folgenden wird erläutert, wie die Methode eingebunden ist und wie sie mit den anderen Komponenten der Klasse CDialog zusammenhängt. Ich werde das in zwei Schritten erklären. Sie können den ersten Schritt jedoch überspringen, wenn Sie nicht beabsichtigen, Farben zu definieren.

Step 1: Definition der Farben der Themes

Es ist notwendig, die Farben zu definieren, damit das Programm die Alternativen kennt, wenn ein Theme-Wechsel aufgerufen wird. In dieser Implementierung verwendet unsere Methode spezifische Farbdefinitionen für dunkle und helle Farbmodi. Dabei kann es sich um vordefinierte Konstanten handeln oder um die Übergabe von Parametern.    

// Theme colors that can be defined elsewhere in our program
const color DARK_THEME_BG = clrBlack;
const color DARK_THEME_BORDER = clrGray;
const color LIGHT_THEME_BG = clrWhite;
const color LIGHT_THEME_BORDER = clrSilver;


Schritt 2: Die Methode zum Aktualisieren der Farben des Themes

Diese Funktion prüft, ob darkTheme aktiv ist (true oder false) und wendet die entsprechenden Farben auf die Hauptkomponenten an: der weiße Rand (m_white_border) wird mit den Hintergrund- und Randfarben aktualisiert; der Hintergrund (m_background) passt seine Hintergrund- und Randfarben an; die Überschrift (m_caption) ändert die Text- und Hintergrundfarben der Titelleiste; und der Client-Bereich (m_client_area) wendet Farbänderungen auf den Client-Bereich an. Schließlich ruft die Funktion Redraw() auf, um sicherzustellen, dass das neue Theme visuell angewendet wird, ohne dass Objekte neu erstellt werden. Wenn Sie den zweiten Schritt übersprungen haben, funktionieren die hervorgehobenen Farbdefinitionen nicht und die Farbe muss z. B. als ClrBlack oder ClrBlue usw. eingegeben werden.


//+------------------------------------------------------------------+
//| Method for dynamic theme updates                                 |
//+------------------------------------------------------------------+


void CDialog::UpdateThemeColors(bool darkTheme)
{
   color backgroundColor = darkTheme ? DARK_THEME_BG : LIGHT_THEME_BG;
   color borderColor = darkTheme ? DARK_THEME_BORDER : LIGHT_THEME_BORDER;

   // Update White Border colors
   m_white_border.ColorBackground(backgroundColor);
   m_white_border.ColorBorder(borderColor);

   // Update Background colors
   m_background.ColorBackground(backgroundColor);
   m_background.ColorBorder(borderColor);

   // Update Caption colors (optional for text-based themes)
   m_caption.Color(darkTheme ? clrWhite : clrBlack);
   m_caption.ColorBackground(backgroundColor);

   // Update Client Area colors
   m_client_area.ColorBackground(backgroundColor);
   m_client_area.ColorBorder(borderColor);

   // Redraw the controls to reflect the theme changes
   Redraw();
}


Die Klasse CButton für die Theme-Verwaltung

Mit den gleichen Begriffen wie oben haben wir die Methoden SetTextColor, SetBackgroundColor und SetBorderColor zur Klasse CButton hinzugefügt. Mit diesen Methoden können wir die Text-, Hintergrund- und Rahmenfarbe der Schaltfläche festlegen. Der folgende Codeabschnitt zeigt die Implementierung der Methoden.

 //--- theme methods
   void              SetTextColor(color clr)       { m_button.Color(clr);                           }
   void              SetBackgroundColor(color clr) { m_button.BackColor(clr);                       }
   void              SetBorderColor(color clr)     { m_button.BorderColor(clr);                     }

Das Standardprogramm von MQL5 CButton

//+------------------------------------------------------------------+
//|                                                       Button.mqh |
//|                             Copyright 2000-2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Class CButton                                                    |
//| Usage: control that is displayed by                              |
//|             the CChartObjectButton object                        |
//+------------------------------------------------------------------+
class CButton : public CWndObj
  {
private:
   CChartObjectButton m_button;             // chart object

public:
                     CButton(void);
                    ~CButton(void);
   //--- create
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
   //--- state
   bool              Pressed(void)          const { return(m_button.State());                       }
   bool              Pressed(const bool pressed)  { return(m_button.State(pressed));                }
   //--- properties
   bool              Locking(void)          const { return(IS_CAN_LOCK);                            }
   void              Locking(const bool flag);

protected:
   //--- handlers of object settings
   virtual bool      OnSetText(void)              { return(m_button.Description(m_text));           }
   virtual bool      OnSetColor(void)             { return(m_button.Color(m_color));                }
   virtual bool      OnSetColorBackground(void)   { return(m_button.BackColor(m_color_background)); }
   virtual bool      OnSetColorBorder(void)       { return(m_button.BorderColor(m_color_border));   }
   virtual bool      OnSetFont(void)              { return(m_button.Font(m_font));                  }
   virtual bool      OnSetFontSize(void)          { return(m_button.FontSize(m_font_size));         }
   //--- internal event handlers
   virtual bool      OnCreate(void);
   virtual bool      OnShow(void);
   virtual bool      OnHide(void);
   virtual bool      OnMove(void);
   virtual bool      OnResize(void);
   //--- íîâûå îáðàáîò÷èêè
   virtual bool      OnMouseDown(void);
   virtual bool      OnMouseUp(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CButton::CButton(void)
  {
   m_color           =CONTROLS_BUTTON_COLOR;
   m_color_background=CONTROLS_BUTTON_COLOR_BG;
   m_color_border    =CONTROLS_BUTTON_COLOR_BORDER;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CButton::~CButton(void)
  {
  }
//+------------------------------------------------------------------+
//| Create a control                                                 |
//+------------------------------------------------------------------+
bool CButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
//--- call method of the parent class
   if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
//--- create the chart object
   if(!m_button.Create(chart,name,subwin,x1,y1,Width(),Height()))
      return(false);
//--- call the settings handler
   return(OnChange());
  }
//+------------------------------------------------------------------+
//| Locking flag                                                     |
//+------------------------------------------------------------------+
void CButton::Locking(const bool flag)
  {
   if(flag)
      PropFlagsSet(WND_PROP_FLAG_CAN_LOCK);
   else
      PropFlagsReset(WND_PROP_FLAG_CAN_LOCK);
  }
//+------------------------------------------------------------------+
//| Create object on chart                                           |
//+------------------------------------------------------------------+
bool CButton::OnCreate(void)
  {
//--- create the chart object by previously set parameters
   return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
  }
//+------------------------------------------------------------------+
//| Display object on chart                                          |
//+------------------------------------------------------------------+
bool CButton::OnShow(void)
  {
   return(m_button.Timeframes(OBJ_ALL_PERIODS));
  }
//+------------------------------------------------------------------+
//| Hide object from chart                                           |
//+------------------------------------------------------------------+
bool CButton::OnHide(void)
  {
   return(m_button.Timeframes(OBJ_NO_PERIODS));
  }
//+------------------------------------------------------------------+
//| Absolute movement of the chart object                            |
//+------------------------------------------------------------------+
bool CButton::OnMove(void)
  {
//--- position the chart object
   return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top));
  }
//+------------------------------------------------------------------+
//| Resize the chart object                                          |
//+------------------------------------------------------------------+
bool CButton::OnResize(void)
  {
//--- resize the chart object
   return(m_button.X_Size(m_rect.Width()) && m_button.Y_Size(m_rect.Height()));
  }
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button                        |
//+------------------------------------------------------------------+
bool CButton::OnMouseDown(void)
  {
   if(!IS_CAN_LOCK)
      Pressed(!Pressed());
//--- call of the method of the parent class
   return(CWnd::OnMouseDown());
  }
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button                        |
//+------------------------------------------------------------------+
bool CButton::OnMouseUp(void)
  {
//--- depress the button if it is not fixed
   if(m_button.State() && !IS_CAN_LOCK)
      m_button.State(false);
//--- call of the method of the parent class
   return(CWnd::OnMouseUp());
  }
//+------------------------------------------------------------------+


CButton mit integrierter Methode für die Theme-Verwaltung:

Siehe den hervorgehobenen Abschnitt.

//+------------------------------------------------------------------+
//|                                                       Button.mqh |
//|                             Copyright 2000-2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Class CButton                                                    |
//| Usage: control that is displayed by                              |
//|             the CChartObjectButton object                        |
//+------------------------------------------------------------------+
class CButton : public CWndObj
  {
private:
   CChartObjectButton m_button;             // chart object

public:
                     CButton(void);
                    ~CButton(void);
   //--- create
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
   //--- state
   bool              Pressed(void)          const { return(m_button.State());                       }
   bool              Pressed(const bool pressed)  { return(m_button.State(pressed));                }
   //--- properties
   bool              Locking(void)          const { return(IS_CAN_LOCK);                            }
   void              Locking(const bool flag);
   
   //--- theme methods
   void              SetTextColor(color clr)       { m_button.Color(clr);                           }
   void              SetBackgroundColor(color clr) { m_button.BackColor(clr);                       }
   void              SetBorderColor(color clr)     { m_button.BorderColor(clr);                     }

protected:
   //--- handlers of object settings
   virtual bool      OnSetText(void)              { return(m_button.Description(m_text));           }
   virtual bool      OnSetColor(void)             { return(m_button.Color(m_color));                }
   virtual bool      OnSetColorBackground(void)   { return(m_button.BackColor(m_color_background)); }
   virtual bool      OnSetColorBorder(void)       { return(m_button.BorderColor(m_color_border));   }
   virtual bool      OnSetFont(void)              { return(m_button.Font(m_font));                  }
   virtual bool      OnSetFontSize(void)          { return(m_button.FontSize(m_font_size));         }
   //--- internal event handlers
   virtual bool      OnCreate(void);
   virtual bool      OnShow(void);
   virtual bool      OnHide(void);
   virtual bool      OnMove(void);
   virtual bool      OnResize(void);
   virtual bool      OnMouseDown(void);
   virtual bool      OnMouseUp(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CButton::CButton(void)
  {
   m_color           =CONTROLS_BUTTON_COLOR;
   m_color_background=CONTROLS_BUTTON_COLOR_BG;
   m_color_border    =CONTROLS_BUTTON_COLOR_BORDER;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CButton::~CButton(void)
  {
  }
//+------------------------------------------------------------------+
//| Create a control                                                 |
//+------------------------------------------------------------------+
bool CButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
//--- call method of the parent class
   if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
//--- create the chart object
   if(!m_button.Create(chart,name,subwin,x1,y1,Width(),Height()))
      return(false);
//--- call the settings handler
   return(OnChange());
  }
//+------------------------------------------------------------------+
//| Locking flag                                                     |
//+------------------------------------------------------------------+
void CButton::Locking(const bool flag)
  {
   if(flag)
      PropFlagsSet(WND_PROP_FLAG_CAN_LOCK);
   else
      PropFlagsReset(WND_PROP_FLAG_CAN_LOCK);
  }
//+------------------------------------------------------------------+
//| Create object on chart                                           |
//+------------------------------------------------------------------+
bool CButton::OnCreate(void)
  {
//--- create the chart object by previously set parameters
   return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
  }
//+------------------------------------------------------------------+
//| Display object on chart                                          |
//+------------------------------------------------------------------+
bool CButton::OnShow(void)
  {
   return(m_button.Timeframes(OBJ_ALL_PERIODS));
  }
//+------------------------------------------------------------------+
//| Hide object from chart                                           |
//+------------------------------------------------------------------+
bool CButton::OnHide(void)
  {
   return(m_button.Timeframes(OBJ_NO_PERIODS));
  }
//+------------------------------------------------------------------+
//| Absolute movement of the chart object                            |
//+------------------------------------------------------------------+
bool CButton::OnMove(void)
  {
//--- position the chart object
   return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top));
  }
//+------------------------------------------------------------------+
//| Resize the chart object                                          |
//+------------------------------------------------------------------+
bool CButton::OnResize(void)
  {
//--- resize the chart object
   return(m_button.X_Size(m_rect.Width()) && m_button.Y_Size(m_rect.Height()));
  }
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button                        |
//+------------------------------------------------------------------+
bool CButton::OnMouseDown(void)
  {
   if(!IS_CAN_LOCK)
      Pressed(!Pressed());
//--- call of the method of the parent class
   return(CWnd::OnMouseDown());
  }
//+------------------------------------------------------------------+
//| Handler of click on the left mouse button                        |
//+------------------------------------------------------------------+
bool CButton::OnMouseUp(void)
  {
//--- depress the button if it is not fixed
   if(m_button.State() && !IS_CAN_LOCK)
      m_button.State(false);
//--- call of the method of the parent class
   return(CWnd::OnMouseUp());
  }
//+------------------------------------------------------------------+


Die Klasse CEdit für die Theme-Verwaltung

Dies ist eine der wichtigsten Klassen in unserem Projekt, die das Eingabefeld steuert, in das wir unsere Nachricht eingeben werden. Standardmäßig sind unser Panel und seine Komponenten auf einen weißen Hintergrund mit schwarzem Text im Vordergrund eingestellt. Wenn wir auf die Schaltfläche zum Wechseln des Themes klicken, ändert sich die Vordergrundfarbe zu Weiß. Während der Entwicklung ist mir jedoch aufgefallen, dass die Farbe des Eingabefeldes unverändert blieb, sodass sie beim Umschalten des Themes gelegentlich mit dem Text verschmolz. Daher müssen wir der Klasse CEdit eine Methode hinzufügen, um den Wechsel des Themes zu handhaben und sicherzustellen, dass das Texteingabefeld mit den Zielen unseres Themes übereinstimmt.

Die Standardklasse CEdit verfügt bereits über Methoden zum Einstellen von Farben (OnSetColor, OnSetColorBackground und OnSetColorBorder). Wir können diese Methoden verwenden, um das Aussehen des CEdit-Objekts zu aktualisieren, wenn sich das Theme ändert. Wir setzen neue Methoden für Theme Switching ein, indem wir diese Terme hinzufügen: SetTextColor-, SetBackgroundColor- und SetBorderColor-Methoden in die CEdit-Klasse. Diese Methoden aktualisieren die jeweiligen Farben und rufen die vorhandenen Methoden (OnSetColor, OnSetColorBackground, OnSetColorBorder) auf, um die Änderungen auf das Chartobjekt anzuwenden.

//+------------------------------------------------------------------+
//| Set text color                                                   |
//+------------------------------------------------------------------+
bool CEdit::SetTextColor(const color clr)
  {
   m_color = clr;
   return(OnSetColor());
  }

//+------------------------------------------------------------------+
//| Set background color                                             |
//+------------------------------------------------------------------+
bool CEdit::SetBackgroundColor(const color clr)
  {
   m_color_background = clr;
   return(OnSetColorBackground());
  }

//+------------------------------------------------------------------+
//| Set border color                                                 |
//+------------------------------------------------------------------+
bool CEdit::SetBorderColor(const color clr)
  {
   m_color_border = clr;
   return(OnSetColorBorder());
  }

Nachfolgend sehen wir uns den unbearbeiteten Quellcode der Klasse CEdit an und werden dann das eingebaute Programm direkt darunter weitergeben.

CEdit-Standard von MQL5:

//+------------------------------------------------------------------+
//|                                                         Edit.mqh |
//|                             Copyright 2000-2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsTxtControls.mqh>
//+------------------------------------------------------------------+
//| Class CEdit                                                      |
//| Usage: control that is displayed by                              |
//|             the CChartObjectEdit object                          |
//+------------------------------------------------------------------+
class CEdit : public CWndObj
  {
private:
   CChartObjectEdit  m_edit;                // chart object
   //--- parameters of the chart object
   bool              m_read_only;           // "read-only" mode flag
   ENUM_ALIGN_MODE   m_align_mode;          // align mode

public:
                     CEdit(void);
                    ~CEdit(void);
   //--- create
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
   //--- chart event handler
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- parameters of the chart object
   bool              ReadOnly(void)         const { return(m_read_only);                          }
   bool              ReadOnly(const bool flag);
   ENUM_ALIGN_MODE   TextAlign(void)        const { return(m_align_mode);                         }
   bool              TextAlign(const ENUM_ALIGN_MODE align);
   //--- data access
   string            Text(void)             const { return(m_edit.Description());                 }
   bool              Text(const string value)     { return(CWndObj::Text(value));                 }

protected:
   //--- handlers of object events
   virtual bool      OnObjectEndEdit(void);
   //--- handlers of object settings
   virtual bool      OnSetText(void)              { return(m_edit.Description(m_text));           }
   virtual bool      OnSetColor(void)             { return(m_edit.Color(m_color));                }
   virtual bool      OnSetColorBackground(void)   { return(m_edit.BackColor(m_color_background)); }
   virtual bool      OnSetColorBorder(void)       { return(m_edit.BorderColor(m_color_border));   }
   virtual bool      OnSetFont(void)              { return(m_edit.Font(m_font));                  }
   virtual bool      OnSetFontSize(void)          { return(m_edit.FontSize(m_font_size));         }
   virtual bool      OnSetZOrder(void)            { return(m_edit.Z_Order(m_zorder));             }
   //--- internal event handlers
   virtual bool      OnCreate(void);
   virtual bool      OnShow(void);
   virtual bool      OnHide(void);
   virtual bool      OnMove(void);
   virtual bool      OnResize(void);
   virtual bool      OnChange(void);
   virtual bool      OnClick(void);
  };
//+------------------------------------------------------------------+
//| Common handler of chart events                                   |
//+------------------------------------------------------------------+
bool CEdit::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   if(m_name==sparam && id==CHARTEVENT_OBJECT_ENDEDIT)
      return(OnObjectEndEdit());
//--- event was not handled
   return(CWndObj::OnEvent(id,lparam,dparam,sparam));
  }
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CEdit::CEdit(void) : m_read_only(false),
                     m_align_mode(ALIGN_LEFT)
  {
   m_color           =CONTROLS_EDIT_COLOR;
   m_color_background=CONTROLS_EDIT_COLOR_BG;
   m_color_border    =CONTROLS_EDIT_COLOR_BORDER;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CEdit::~CEdit(void)
  {
  }
//+------------------------------------------------------------------+
//| Create a control                                                 |
//+------------------------------------------------------------------+
bool CEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
//--- call method of the parent class
   if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
//--- create the chart object
   if(!m_edit.Create(chart,name,subwin,x1,y1,Width(),Height()))
      return(false);
//--- call the settings handler
   return(OnChange());
  }
//+------------------------------------------------------------------+
//| Set parameter                                                    |
//+------------------------------------------------------------------+
bool CEdit::ReadOnly(const bool flag)
  {
//--- save new value of parameter
   m_read_only=flag;
//--- set up the chart object
   return(m_edit.ReadOnly(flag));
  }
//+------------------------------------------------------------------+
//| Set parameter                                                    |
//+------------------------------------------------------------------+
bool CEdit::TextAlign(const ENUM_ALIGN_MODE align)
  {
//--- save new value of parameter
   m_align_mode=align;
//--- set up the chart object
   return(m_edit.TextAlign(align));
  }
//+------------------------------------------------------------------+
//| Create object on chart                                           |
//+------------------------------------------------------------------+
bool CEdit::OnCreate(void)
  {
//--- create the chart object by previously set parameters
   return(m_edit.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
  }
//+------------------------------------------------------------------+
//| Display object on chart                                          |
//+------------------------------------------------------------------+
bool CEdit::OnShow(void)
  {
   return(m_edit.Timeframes(OBJ_ALL_PERIODS));
  }
//+------------------------------------------------------------------+
//| Hide object from chart                                           |
//+------------------------------------------------------------------+
bool CEdit::OnHide(void)
  {
   return(m_edit.Timeframes(OBJ_NO_PERIODS));
  }
//+------------------------------------------------------------------+
//| Absolute movement of the chart object                            |
//+------------------------------------------------------------------+
bool CEdit::OnMove(void)
  {
//--- position the chart object
   return(m_edit.X_Distance(m_rect.left) && m_edit.Y_Distance(m_rect.top));
  }
//+------------------------------------------------------------------+
//| Resize the chart object                                          |
//+------------------------------------------------------------------+
bool CEdit::OnResize(void)
  {
//--- resize the chart object
   return(m_edit.X_Size(m_rect.Width()) && m_edit.Y_Size(m_rect.Height()));
  }
//+------------------------------------------------------------------+
//| Set up the chart object                                          |
//+------------------------------------------------------------------+
bool CEdit::OnChange(void)
  {
//--- set up the chart object
   return(CWndObj::OnChange() && ReadOnly(m_read_only) && TextAlign(m_align_mode));
  }
//+------------------------------------------------------------------+
//| Handler of the "End of editing" event                            |
//+------------------------------------------------------------------+
bool CEdit::OnObjectEndEdit(void)
  {
//--- send the ON_END_EDIT notification
   EventChartCustom(CONTROLS_SELF_MESSAGE,ON_END_EDIT,m_id,0.0,m_name);
//--- handled
   return(true);
  }
//+------------------------------------------------------------------+
//| Handler of the "click" event                                     |
//+------------------------------------------------------------------+
bool CEdit::OnClick(void)
  {
//--- if editing is enabled, send the ON_START_EDIT notification
   if(!m_read_only)
     {
      EventChartCustom(CONTROLS_SELF_MESSAGE,ON_START_EDIT,m_id,0.0,m_name);
      //--- handled
      return(true);
     }
//--- else send the ON_CLICK notification
   return(CWnd::OnClick());
  }
//+------------------------------------------------------------------+


CEdit mit integrierter Theme Management Methode:

Siehe die hervorgehobenen Abschnitte.

//+------------------------------------------------------------------+
//|                                                         Edit.mqh |
//|                             Copyright 2000-2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "WndObj.mqh"
#include <ChartObjects\ChartObjectsTxtControls.mqh>

//+------------------------------------------------------------------+
//| Class CEdit                                                      |
//| Usage: control that is displayed by                              |
//|             the CChartObjectEdit object                          |
//+------------------------------------------------------------------+
class CEdit : public CWndObj
  {
private:
   CChartObjectEdit  m_edit;                // chart object
   //--- parameters of the chart object
   bool              m_read_only;           // "read-only" mode flag
   ENUM_ALIGN_MODE   m_align_mode;          // align mode

public:
                     CEdit(void);
                    ~CEdit(void);
   //--- create
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
   //--- chart event handler
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
   //--- parameters of the chart object
   bool              ReadOnly(void)         const { return(m_read_only);                          }
   bool              ReadOnly(const bool flag);
   ENUM_ALIGN_MODE   TextAlign(void)        const { return(m_align_mode);                         }
   bool              TextAlign(const ENUM_ALIGN_MODE align);
   //--- data access
   string            Text(void)             const { return(m_edit.Description());                 }
   bool              Text(const string value)     { return(CWndObj::Text(value));                 }
   //--- theme handling
   bool              SetTextColor(const color clr);
   bool              SetBackgroundColor(const color clr);
   bool              SetBorderColor(const color clr);

protected:
   //--- handlers of object events
   virtual bool      OnObjectEndEdit(void);
   //--- handlers of object settings
   virtual bool      OnSetText(void)              { return(m_edit.Description(m_text));           }
   virtual bool      OnSetColor(void)             { return(m_edit.Color(m_color));                }
   virtual bool      OnSetColorBackground(void)   { return(m_edit.BackColor(m_color_background)); }
   virtual bool      OnSetColorBorder(void)       { return(m_edit.BorderColor(m_color_border));   }
   virtual bool      OnSetFont(void)              { return(m_edit.Font(m_font));                  }
   virtual bool      OnSetFontSize(void)          { return(m_edit.FontSize(m_font_size));         }
   virtual bool      OnSetZOrder(void)            { return(m_edit.Z_Order(m_zorder));             }
   //--- internal event handlers
   virtual bool      OnCreate(void);
   virtual bool      OnShow(void);
   virtual bool      OnHide(void);
   virtual bool      OnMove(void);
   virtual bool      OnResize(void);
   virtual bool      OnChange(void);
   virtual bool      OnClick(void);
  };

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CEdit::CEdit(void) : m_read_only(false),
                     m_align_mode(ALIGN_LEFT)
  {
   m_color           =CONTROLS_EDIT_COLOR;
   m_color_background=CONTROLS_EDIT_COLOR_BG;
   m_color_border    =CONTROLS_EDIT_COLOR_BORDER;
  }

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CEdit::~CEdit(void)
  {
  }

//+------------------------------------------------------------------+
//| Create a control                                                 |
//+------------------------------------------------------------------+
bool CEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
   //--- call method of the parent class
   if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
   //--- create the chart object
   if(!m_edit.Create(chart,name,subwin,x1,y1,Width(),Height()))
      return(false);
   //--- call the settings handler
   return(OnChange());
  }

//+------------------------------------------------------------------+
//| Set parameter                                                    |
//+------------------------------------------------------------------+
bool CEdit::ReadOnly(const bool flag)
  {
   //--- save new value of parameter
   m_read_only=flag;
   //--- set up the chart object
   return(m_edit.ReadOnly(flag));
  }

//+------------------------------------------------------------------+
//| Set parameter                                                    |
//+------------------------------------------------------------------+
bool CEdit::TextAlign(const ENUM_ALIGN_MODE align)
  {
   //--- save new value of parameter
   m_align_mode=align;
   //--- set up the chart object
   return(m_edit.TextAlign(align));
  }

//+------------------------------------------------------------------+
//| Set text color                                                   |
//+------------------------------------------------------------------+
bool CEdit::SetTextColor(const color clr)
  {
   m_color = clr;
   return(OnSetColor());
  }

//+------------------------------------------------------------------+
//| Set background color                                             |
//+------------------------------------------------------------------+
bool CEdit::SetBackgroundColor(const color clr)
  {
   m_color_background = clr;
   return(OnSetColorBackground());
  }

//+------------------------------------------------------------------+
//| Set border color                                                 |
//+------------------------------------------------------------------+
bool CEdit::SetBorderColor(const color clr)
  {
   m_color_border = clr;
   return(OnSetColorBorder());
  }

//+------------------------------------------------------------------+
//| Create object on chart                                           |
//+------------------------------------------------------------------+
bool CEdit::OnCreate(void)
  {
   //--- create the chart object by previously set parameters
   return(m_edit.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height()));
  }

//+------------------------------------------------------------------+
//| Display object on chart                                          |
//+------------------------------------------------------------------+
bool CEdit::OnShow(void)
  {
   return(m_edit.Timeframes(OBJ_ALL_PERIODS));
  }

//+------------------------------------------------------------------+
//| Hide object from chart                                           |
//+------------------------------------------------------------------+
bool CEdit::OnHide(void)
  {
   return(m_edit.Timeframes(OBJ_NO_PERIODS));
  }

//+------------------------------------------------------------------+
//| Absolute movement of the chart object                            |
//+------------------------------------------------------------------+
bool CEdit::OnMove(void)
  {
   //--- position the chart object
   return(m_edit.X_Distance(m_rect.left) && m_edit.Y_Distance(m_rect.top));
  }

//+------------------------------------------------------------------+
//| Resize the chart object                                          |
//+------------------------------------------------------------------+
bool CEdit::OnResize(void)
  {
   //--- resize the chart object
   return(m_edit.X_Size(m_rect.Width()) && m_edit.Y_Size(m_rect.Height()));
  }

//+------------------------------------------------------------------+
//| Set up the chart object                                          |
//+------------------------------------------------------------------+
bool CEdit::OnChange(void)
  {
   //--- set up the chart object
   return(CWndObj::OnChange() && ReadOnly(m_read_only) && TextAlign(m_align_mode));
  }

//+------------------------------------------------------------------+
//| Handler of the "End of editing" event                            |
//+------------------------------------------------------------------+
bool CEdit::OnObjectEndEdit(void)
  {
   //--- send the ON_END_EDIT notification
   EventChartCustom(CONTROLS_SELF_MESSAGE,ON_END_EDIT,m_id,0.0,m_name);
   //--- handled
   return(true);
  }

//+------------------------------------------------------------------+
//| Handler of the "click" event                                     |
//+------------------------------------------------------------------+
bool CEdit::OnClick(void)
  {
   //--- if editing is enabled, send the ON_START_EDIT notification
   if(!m_read_only)
     {
      EventChartCustom(CONTROLS_SELF_MESSAGE,ON_START_EDIT,m_id,0.0,m_name);
      //--- handled
      return(true);
     }
   //--- else send the ON_CLICK notification
   return(CWnd::OnClick());
  }

//+------------------------------------------------------------------+
Wir haben unsere Control-Include-Dateien für das Admin-Panel erfolgreich vorbereitet und sind der Fertigstellung unseres Projekts näher als je zuvor. Im nächsten Abschnitt werden wir unsere Bemühungen abschließen, indem wir den Code des Admin-Panels Expert Advisor so anpassen, dass der Wechsel des Themes unterstützt wird, um mit der jüngsten Entwicklung übereinzustimmen.

Anpassen des Admin-Panels für den Theme-Wechsel.

 In unserer Theme-Verwaltung gibt es logischerweise vier Schlüsselbereiche.

  • Die Funktion zum Wechseln des Farbmodus in unserem Admin-Panel muss sich um die boolesche Variable darkTheme und die Funktion UpdateThemeColors() drehen. Und so funktioniert sie:

bool darkTheme = false;

  • Das obige Flag bestimmt, ob das aktuelle Theme dunkel oder hell ist. Sie wird durch Drücken von toggleThemeButton umgeschaltet, wie unten dargestellt.

void OnToggleThemeButtonClick()
{
    darkTheme = !darkTheme;
    UpdateThemeColors();
    Print("Theme toggled: ", darkTheme ? "Dark" : "Light");
}

  • Ein Klick auf die Schaltfläche zum Umschalten des Themes ruft diese Funktion auf, die das Flag darkTheme umkehrt und anschließend das Theme der Nutzeroberfläche über UpdateThemeColors() aktualisiert.

void UpdateThemeColors()
{
    // Determine colors based on the current theme
    color textColor = darkTheme ? clrWhite : clrBlack;
    color buttonBgColor = darkTheme ? clrDarkSlateGray : clrGainsboro;
    color borderColor = darkTheme ? clrSlateGray : clrGray;
    color bgColor     = darkTheme ? clrDarkBlue : clrWhite;

    // Set text box colors
    inputBox.SetTextColor(textColor);
    inputBox.SetBackgroundColor(bgColor);
    inputBox.SetBorderColor(borderColor);

    // Update button colors
    UpdateButtonTheme(clearButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(sendButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(toggleThemeButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(changeFontButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(minimizeButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(maximizeButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(closeButton, textColor, buttonBgColor, borderColor);

    // Update quick message buttons
    for (int i = 0; i < ArraySize(quickMessageButtons); i++)
    {
        UpdateButtonTheme(quickMessageButtons[i], textColor, buttonBgColor, borderColor);
    }

    // Update character counter color
    charCounter.Color(textColor);

    // Redraw chart to apply changes
    ChartRedraw();
}

 Basierend auf dem Flag darkTheme, haben wir verschiedene Farben für Text, Schaltflächenhintergründe, Rahmen und Hintergründe gewählt. Farben werden wie folgt auf verschiedene UI-Komponenten angewendet:

  • Text Box (inputBox): Die Funktionen SetTextColor, SetBackgroundColor und SetBorderColor werden verwendet, um das Design anzuwenden.
  • Buttons: Die Funktion UpdateButtonTheme() wird für jede Schaltfläche aufgerufen, wobei die Textfarbe, die Hintergrundfarbe und die Farbe des Rahmens wie festgelegt eingestellt werden.
  • Character Counter: Legt die Farbe direkt fest, wenn wir auf die Schaltfläche „Theme“ klicken.

//Theme button application
void UpdateButtonTheme(CButton &button, color textColor, color bgColor, color borderColor)
{
    button.SetTextColor(textColor);
    button.SetBackgroundColor(bgColor);
    button.SetBorderColor(borderColor);
}

Wir haben oben eine Hilfsfunktion verwendet, um alle relevanten Theme-bezogenen Farbeinstellungen auf jede Schaltfläche anzuwenden. Dadurch wird der sich wiederholende Code bereinigt und die Konsistenz zwischen den Schaltflächen gewährleistet. Wenn man alle Codeschnipsel zusammenfasst und sie in das Hauptprogramm des Admin-Panels integriert, haben wir alle Funktionen, die dem Ziel entsprechen.


Endgültiger Code und Ergebnisse

Hier ist der endgültige Entwurf unseres Programms mit den neuen Funktionen.


//+------------------------------------------------------------------+
//|                                             Admin Panel.mq5      |
//|                     Copyright 2024, Clemence Benjamin            |
//|     https://www.mql5.com/en/users/billionaire2024/seller         |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Clemence Benjamin"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.12"

#include <Trade\Trade.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Edit.mqh>
#include <Controls\Label.mqh>

// Input parameters
input string QuickMessage1 = "Updates";
input string QuickMessage2 = "Close all";
input string QuickMessage3 = "In deep profits";
input string QuickMessage4 = "Hold position";
input string QuickMessage5 = "Swing Entry";
input string QuickMessage6 = "Scalp Entry";
input string QuickMessage7 = "Book profit";
input string QuickMessage8 = "Invalid Signal";
input string InputChatId = "Enter Chat ID from Telegram bot API";
input string InputBotToken = "Enter BOT TOKEN from your Telegram bot";

// Global variables
CDialog adminPanel;
CButton sendButton, clearButton, changeFontButton, toggleThemeButton;
CButton quickMessageButtons[8], minimizeButton, maximizeButton, closeButton;
CEdit inputBox;
CLabel charCounter;
bool minimized = false;
bool darkTheme = false;
int MAX_MESSAGE_LENGTH = 4096;
string availableFonts[] = { "Arial", "Courier New", "Verdana", "Times New Roman" };
int currentFontIndex = 0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    // Initialize the Dialog
    if (!adminPanel.Create(ChartID(), "Admin Panel", 0, 30, 30, 500, 500))
    {
        Print("Failed to create dialog");
        return INIT_FAILED;
    }

    // Create controls
    if (!CreateControls())
    {
        Print("Control creation failed");
        return INIT_FAILED;
    }

    adminPanel.Show();
    UpdateThemeColors();

    Print("Initialization complete");
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Create necessary UI controls                                     |
//+------------------------------------------------------------------+
bool CreateControls()
{
    long chart_id = ChartID();

    // Create the input box
    if (!inputBox.Create(chart_id, "InputBox", 0, 5, 25, 460, 95))
    {
        Print("Failed to create input box");
        return false;
    }
    adminPanel.Add(inputBox);

    // Character counter
    if (!charCounter.Create(chart_id, "CharCounter", 0, 380, 5, 460, 25))
    {
        Print("Failed to create character counter");
        return false;
    }
    charCounter.Text("0/" + IntegerToString(MAX_MESSAGE_LENGTH));
    adminPanel.Add(charCounter);

    // Clear button
    if (!clearButton.Create(chart_id, "ClearButton", 0, 235, 95, 345, 125))
    {
        Print("Failed to create clear button");
        return false;
    }
    clearButton.Text("Clear");
    adminPanel.Add(clearButton);

    // Send button
    if (!sendButton.Create(chart_id, "SendButton", 0, 350, 95, 460, 125))
    {
        Print("Failed to create send button");
        return false;
    }
    sendButton.Text("Send");
    adminPanel.Add(sendButton);

    // Change font button
    if (!changeFontButton.Create(chart_id, "ChangeFontButton", 0, 95, 95, 230, 115))
    {
        Print("Failed to create change font button");
        return false;
    }
    changeFontButton.Text("Font<>");
    adminPanel.Add(changeFontButton);

    // Toggle theme button
    if (!toggleThemeButton.Create(chart_id, "ToggleThemeButton", 0, 5, 95, 90, 115))
    {
        Print("Failed to create toggle theme button");
        return false;
    }
    toggleThemeButton.Text("Theme<>");
    adminPanel.Add(toggleThemeButton);

    // Minimize button
    if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0))
    {
        Print("Failed to create minimize button");
        return false;
    }
    minimizeButton.Text("_");
    adminPanel.Add(minimizeButton);

    // Maximize button
    if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0))
    {
        Print("Failed to create maximize button");
        return false;
    }
    maximizeButton.Text("[ ]");
    adminPanel.Add(maximizeButton);

    // Close button
    if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0))
    {
        Print("Failed to create close button");
        return false;
    }
    closeButton.Text("X");
    adminPanel.Add(closeButton);

    // Quick messages
    return CreateQuickMessageButtons();
}

//+------------------------------------------------------------------+
//| Create quick message buttons                                     |
//+------------------------------------------------------------------+
bool CreateQuickMessageButtons()
{
    string quickMessages[8] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 };
    int startX = 5, startY = 160, width = 222, height = 65, spacing = 5;

    for (int i = 0; i < 8; i++)
    {
        if (!quickMessageButtons[i].Create(ChartID(), "QuickMessageButton" + IntegerToString(i + 1), 0, startX + (i % 2) * (width + spacing), startY + (i / 2) * (height + spacing), startX + (i % 2) * (width + spacing) + width, startY + (i / 2) * (height + spacing) + height))
        {
            Print("Failed to create quick message button ", i + 1);
            return false;
        }
        quickMessageButtons[i].Text(quickMessages[i]);
        adminPanel.Add(quickMessageButtons[i]);
    }
    return true;
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    adminPanel.Destroy();
    Print("Deinitialization complete");
}

//+------------------------------------------------------------------+
//| Handle chart events                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
    switch (id)
    {
        case CHARTEVENT_OBJECT_CLICK:
            if (sparam == "SendButton") OnSendButtonClick();
            else if (sparam == "ClearButton") OnClearButtonClick();
            else if (sparam == "ChangeFontButton") OnChangeFontButtonClick();
            else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick();
            else if (sparam == "MinimizeButton") OnMinimizeButtonClick();
            else if (sparam == "MaximizeButton") OnMaximizeButtonClick();
            else if (sparam == "CloseButton") OnCloseButtonClick();
            else if (StringFind(sparam, "QuickMessageButton") != -1)
            {
                long index = StringToInteger(StringSubstr(sparam, 18));
                OnQuickMessageButtonClick(index - 1);
            }
            break;

        case CHARTEVENT_OBJECT_ENDEDIT:
            if (sparam == "InputBox") OnInputChange();
            break;
    }
}

//+------------------------------------------------------------------+
//| Handle custom message send button click                          |
//+------------------------------------------------------------------+
void OnSendButtonClick()
{
    string message = inputBox.Text();
    if (message != "")
    {
        if (SendMessageToTelegram(message))
            Print("Custom message sent: ", message);
        else
            Print("Failed to send custom message.");
    }
    else
    {
        Print("No message entered.");
    }
}

//+------------------------------------------------------------------+
//| Handle clear button click                                        |
//+------------------------------------------------------------------+
void OnClearButtonClick()
{
    inputBox.Text("");
    OnInputChange();
    Print("Input box cleared.");
}

//+------------------------------------------------------------------+
//| Handle quick message button click                                |
//+------------------------------------------------------------------+
void OnQuickMessageButtonClick(int index)
{
    string quickMessages[8] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 };
    string message = quickMessages[index];

    if (SendMessageToTelegram(message))
        Print("Quick message sent: ", message);
    else
        Print("Failed to send quick message.");
}

//+------------------------------------------------------------------+
//| Update character counter                                         |
//+------------------------------------------------------------------+
void OnInputChange()
{
    int currentLength = StringLen(inputBox.Text());
    charCounter.Text(IntegerToString(currentLength) + "/" + IntegerToString(MAX_MESSAGE_LENGTH));
    ChartRedraw();
}

//+------------------------------------------------------------------+
//| Handle toggle theme button click                                 |
//+------------------------------------------------------------------+
void OnToggleThemeButtonClick()
{
    darkTheme = !darkTheme;
    UpdateThemeColors();
    Print("Theme toggled: ", darkTheme ? "Dark" : "Light");
}

//+------------------------------------------------------------------+
//| Update theme colors for the panel                                |
//+------------------------------------------------------------------+
void UpdateThemeColors()
{
    // Use the dialog's theme update method as a placeholder.
    adminPanel.UpdateThemeColors(darkTheme);

    color textColor = darkTheme ? clrWhite : clrBlack;
    color buttonBgColor = darkTheme ? clrDarkSlateGray : clrGainsboro;
    color borderColor = darkTheme ? clrSlateGray : clrGray;
    color bgColor     = darkTheme?  clrDarkBlue : clrWhite;

          inputBox.SetTextColor(textColor);
          inputBox.SetBackgroundColor(bgColor);
          inputBox.SetBorderColor(borderColor);

    UpdateButtonTheme(clearButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(sendButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(toggleThemeButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(changeFontButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(minimizeButton, textColor, buttonBgColor, borderColor);
    UpdateButtonTheme(maximizeButton, textColor, buttonBgColor,borderColor);
    UpdateButtonTheme(closeButton, textColor, buttonBgColor, borderColor);
    

    for (int i = 0; i < ArraySize(quickMessageButtons); i++)
    {
        UpdateButtonTheme(quickMessageButtons[i], textColor, buttonBgColor, borderColor);
    }

    charCounter.Color(textColor);

    ChartRedraw();
}

//+------------------------------------------------------------------+
//| Apply theme settings to a button                                 |
//+------------------------------------------------------------------+
void UpdateButtonTheme(CButton &button, color textColor, color bgColor, color borderColor)
{
    button.SetTextColor(textColor);
    button.SetBackgroundColor(bgColor);
    button.SetBorderColor(borderColor);
}

//+------------------------------------------------------------------+
//| Handle change font button click                                  |
//+------------------------------------------------------------------+
void OnChangeFontButtonClick()
{
    currentFontIndex = (currentFontIndex + 1) % ArraySize(availableFonts);

    inputBox.Font(availableFonts[currentFontIndex]);
    clearButton.Font(availableFonts[currentFontIndex]);
    sendButton.Font(availableFonts[currentFontIndex]);
    toggleThemeButton.Font(availableFonts[currentFontIndex]);
    changeFontButton.Font(availableFonts[currentFontIndex]);

    for (int i = 0; i < ArraySize(quickMessageButtons); i++)
    {
        quickMessageButtons[i].Font(availableFonts[currentFontIndex]);
    }

    Print("Font changed to: ", availableFonts[currentFontIndex]);
    ChartRedraw();
}

//+------------------------------------------------------------------+
//| Handle minimize button click                                     |
//+------------------------------------------------------------------+
void OnMinimizeButtonClick()
{
    minimized = true;
    adminPanel.Hide();
    minimizeButton.Hide();
    maximizeButton.Show();
    closeButton.Show();
    Print("Panel minimized.");
}

//+------------------------------------------------------------------+
//| Handle maximize button click                                     |
//+------------------------------------------------------------------+
void OnMaximizeButtonClick()
{
    if (minimized)
    {
        adminPanel.Show();
        minimizeButton.Show();
        maximizeButton.Hide();
        closeButton.Hide();
        Print("Panel maximized.");
    }
}

//+------------------------------------------------------------------+
//| Handle close button click                                        |
//+------------------------------------------------------------------+
void OnCloseButtonClick()
{
    ExpertRemove();
    Print("Admin Panel closed.");
}

//+------------------------------------------------------------------+
//| Send the message to Telegram                                     |
//+------------------------------------------------------------------+
bool SendMessageToTelegram(string message)
{
    string url = "https://api.telegram.org/bot" + InputBotToken + "/sendMessage";
    string jsonMessage = "{\"chat_id\":\"" + InputChatId + "\", \"text\":\"" + message + "\"}";
    char post_data[];
    ArrayResize(post_data, StringToCharArray(jsonMessage, post_data, 0, WHOLE_ARRAY) - 1);

    int timeout = 5000;
    char result[];
    string responseHeaders;

    int res = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, post_data, result, responseHeaders);

    if (res == 200)
    {
        Print("Message sent successfully: ", message);
        return true;
    }
    else
    {
        Print("Failed to send message. HTTP code: ", res, " Error code: ", GetLastError());
        Print("Response: ", CharArrayToString(result));
        return false;
    }
}


Nach erfolgreicher Kompilierung haben wir unser Programm wie unten gezeigt gestartet und dabei einige beeindruckende Effekte der Theme-schaltflächen gezeigt. Die Funktion zum Wechseln des Themes funktioniert effektiv und verbessert die visuelle Präsentation erheblich. Das Erstaunliche daran ist, dass diese Farben im Code nach Ihren Wünschen optimiert werden können. Außerdem könnten wir Farbeingabeoptionen einbauen, um die Farbanpassung außerhalb des Codes zu ermöglichen.


Erweiterte Administrationsoberfläche

Neue Themetische Administrationsoberfläche

Die folgende Abbildung zeigt alle Operationen, die auf dem Panel ausgeführt werden, einschließlich der Fehlerbehandlung. Das Scheitern beim Senden einer nutzerdefinierten Nachricht kann auf fehlende oder falsche Einträge für Telegram-Bot-Token und Chat-ID zurückgeführt werden. Wie auf dem Bild zu sehen ist, wurden diese Felder leer gelassen. Es ist wichtig, dass diese Daten korrekt eingegeben werden, da sie für den Betrieb entscheidend sind. Bitte denken Sie daran, diese Anmeldedaten sicher aufzubewahren, um unbefugten Zugriff zu verhindern. 

Expert-Log

Expert-Log

Schlussfolgerung

Dies markiert einen weiteren Meilenstein in der Entwicklung unseres Trading Systems Admin Panel. Wir haben erfolgreich Algorithmen für die Theme-Verwaltung in bestehende Klassen integriert, ohne dass dabei Leistungsprobleme mit anderen Plattformfunktionen, die auf denselben Bibliotheken basieren, beobachtet wurden. Diese Fortschritte dienen in erster Linie zu Lern- und Forschungszwecken. Die Änderung von Klassen und die Integration neuer Methoden können sich jedoch positiv auswirken, bergen aber auch die Gefahr unerwünschter Ergebnisse, wenn sie nicht korrekt umgesetzt werden. Unser Projekt ist nun komplexer geworden, da wir sowohl Telegram-Funktionen als auch erweiterte Visualisierungsfunktionen integriert haben.

Ich freue mich über unsere Fortschritte und hoffe, dass Sie aus der Arbeit mit den Bibliotheksdateien in MQL5 wertvolle Erkenntnisse gewonnen haben. Es gibt noch viel mehr, was mit einigen der in diesem Projekt verwendeten Ansätze erreicht werden kann. Ich habe die geänderten Quelldateien unten angehängt. Bitte beachten Sie, dass die Funktion zum Wechseln des Themes auf das Vorhandensein dieser Bibliotheksklassen angewiesen ist. Wenn Sie Probleme haben, sollten Sie eine Neuinstallation des MetaTrader 5 in Erwägung ziehen, um die Systemdateien wiederherzustellen und die Klassen auf ihren Standardzustand zurückzusetzen.

Die Änderungen und Diskussionen zu den MQL5-Bibliotheksdateien, insbesondere zu den GUI-Komponenten, werden nur zu Lehrzwecken bereitgestellt. Die Bearbeitung dieser Dateien kann zwar zu optisch ansprechenden Ergebnissen führen, ist aber mit Vorsicht zu genießen. Die Änderung von Header-Dateien kann zu unerwartetem Verhalten, Instabilität oder Kompatibilitätsproblemen innerhalb Ihrer Handelsanwendungen führen. Es ist wichtig, die vorgenommenen Änderungen genau zu verstehen und Sicherungskopien der Originaldateien zu erstellen. Wir empfehlen, alle Änderungen in einer sicheren Umgebung zu testen, bevor sie in Live-Handelssystemen eingesetzt werden. Der Autor dieses Materials übernimmt keine Verantwortung für Probleme, die sich aus der Bearbeitung von MQL5-Header-Dateien ergeben können.


Zurück zur Inhaltsseite


Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16045

Beigefügte Dateien |
Admin_Panel.mq5 (14.69 KB)
Integrieren Sie Ihr eigenes LLM in EA (Teil 5): Handelsstrategie mit LLMs(II)-LoRA-Tuning entwickeln und testen Integrieren Sie Ihr eigenes LLM in EA (Teil 5): Handelsstrategie mit LLMs(II)-LoRA-Tuning entwickeln und testen
Angesichts der rasanten Entwicklung der künstlichen Intelligenz sind Sprachmodelle (language models, LLMs) heute ein wichtiger Bestandteil der künstlichen Intelligenz, sodass wir darüber nachdenken sollten, wie wir leistungsstarke LLMs in unseren algorithmischen Handel integrieren können. Für die meisten Menschen ist es schwierig, diese leistungsstarken Modelle auf ihre Bedürfnisse abzustimmen, sie lokal einzusetzen und sie dann auf den algorithmischen Handel anzuwenden. In dieser Artikelserie werden wir Schritt für Schritt vorgehen, um dieses Ziel zu erreichen.
Ordinale Kodierung für Nominalvariablen Ordinale Kodierung für Nominalvariablen
In diesem Artikel erörtern und demonstrieren wir, wie man nominale Prädiktoren in numerische Formate umwandelt, die für Algorithmen des maschinellen Lernens geeignet sind, und zwar sowohl mit Python als auch mit MQL5.
Entwicklung eines Replay Systems (Teil 54): Die Geburt des ersten Moduls Entwicklung eines Replay Systems (Teil 54): Die Geburt des ersten Moduls
In diesem Artikel werden wir uns ansehen, wie wir das erste einer Reihe von wirklich funktionalen Modulen für die Verwendung im Replay-/Simulatorsystem zusammenstellen, die auch für andere Zwecke geeignet sein werden. Die Rede ist vom Mausmodul.
MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 42): ADX-Oszillator MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 42): ADX-Oszillator
Der ADX ist ein weiterer relativ beliebter technischer Indikator, der von einigen Händlern verwendet wird, um die Stärke eines vorherrschenden Trends zu messen. Als Kombination von zwei anderen Indikatoren stellt er einen Oszillator dar, dessen Muster wir in diesem Artikel mit Hilfe der MQL5-Assistentengruppe und ihrer Unterstützungsklassen untersuchen.