
Создание торговой панели администратора на MQL5 (Часть III): Расширение встроенных классов для управления темами (II)
Содержание:
- Введение
- Классы в MQL5
- Добавление методов управления темами в (CDialog, CEdit и CButton)
- Управление темами класса CButton
- Управление темами класса CEdit
- Настройка панели администратора для переключения тем
- Окончательный код и результаты
- Заключение
Введение
Мы можем изменять и создавать новые классы библиотек для MQL5. Однако поскольку встроенные библиотеки используются платформой совместно, любые изменения, которые мы вносим в эти файлы, могут как улучшить, так и ухудшить текущие функции платформы. В недавней статье мы кратко обсудили работу с цветом корневого класса Dialog для изменения внешнего вида нашей панели. Хотя наша кнопка переключения темы успешно изменила цвет текста, она не изменила внешний вид панели или цвет фона кнопки.
Благодаря исследованиям мы наконец определили методы безопасной интеграции функций изменения темы в доступные классы. После успешного внедрения этих изменений мы скорректировали алгоритм панели администратора для соответствия новым интегрированным функциям.
Изменение темы прошло успешно
Текущая статья посвящена созданию визуально привлекательной панели, представленной справа. Показанные цвета темы основаны на моем представлении о выборе цветов во время разработки. Их можно оптимизировать в коде в соответствии с предпочтениями других пользователей. Важно выделить ключевые компоненты нашей программы, которые вносят вклад в общую функциональность панели.
Я перечислю их ниже:
- Цвет текста
- Цвет кнопки
- Границы
- Цвет фона
Это наиболее заметные особенности нашей программы. Когда мы инициируем смену темы, каждый компонент должен отреагировать, изменив свои свойства отображения, чтобы отобразить желаемые цвета, определенные в коде. К концу статьи я постараюсь привить вам навыки, необходимые для изменения и расширения доступных классов при работе с интерфейсами.
Классы в MQL5.
Чтобы и новички, и опытные пользователи могли понять изложенное, я хотел бы начать с концепции классов, используемой в MQL5. Ниже приведены определения и ключевые концепции, которые помогут нам понять, как функционируют классы в этой среде программирования.
Классы:
Классы являются основой объектно-ориентированного программирования (ООП) в MQL5, позволяя разработчикам группировать связанные переменные (атрибуты) и функции (методы) в единый блок для представления сложных концепций и поведения в программе.
Выделяют:
- Атрибуты: переменные, хранящие состояние или данные объектов класса.
- Методы: функции, определяющие поведение или действия объектов класса.
Краткое описание основных характеристик класса:
- Инкапсуляция в классе подразумевает объединение данных (переменных) и методов (функций), которые работают с этими данными, обеспечивая их защиту от внешнего доступа и неправомерного использования.
- Наследование позволяет классу наследовать свойства и методы другого класса, способствуя повторному использованию кода и созданию иерархической структуры.
- Полиморфизм позволяет переопределять методы, позволяя подклассам предоставлять конкретные реализации для методов, уже определенных в их родительских классах.
- Абстракция упрощает моделирование сложных систем, сосредотачиваясь только на релевантных данных и методах и скрывая ненужные детали от пользователя.
Расположение заголовочных файлов MQL5
Я использовал типичный фрагмент исходного кода класса MQL5, чтобы помочь нам четко понять классы и их структуры с практической точки зрения. Посмотрите на фрагмент кода ниже. Его конструкцию я объяснил чуть ниже в табличной форме.
//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); };
В этой таблице представлен обзор атрибутов, доступных в приведенных выше фрагментах кода, и их описание.
Атрибуты (свойства) | Описание |
---|---|
bool m_panel_flag; | Флаг, указывающий, видна ли панель. |
bool m_minimized; | Флаг, указывающий, свернуто ли диалоговое окно |
CWnd m_caption; | Управление текстом подписи. |
CWnd m_client_area; | Управление клиентской областью, где находятся другие элементы. |
CRect m_norm_rect; | Координаты для нормального (не минимизированного) состояния. |
CRect m_min_rect; | Координаты для свернутого состояния. |
CWnd m_white_border; | Управление белой рамкой вокруг диалогового окна. |
В этой таблице обобщены методы, используемые в примере кода класса.
Методы | Описание |
---|---|
CDialog(void) | Конструктор, инициализирующий диалог. |
~CDialog(void) | Деструктор для очистки ресурсов. |
Create(...) | Создает диалоговое окно и его элементы управления. |
OnEvent(...) | Обрабатывает события графика для диалога. |
Caption(void) | Возвращает текущий текст подписи. |
Caption(const string text) | Устанавливает текст подписи. |
Add(CWnd *control) | Добавляет элемент управления в клиентскую область с помощью указателя. |
Add(CWnd &control) | Добавляет элемент управления в клиентскую область по ссылке. |
Save(const int file_handle) | Сохраняет состояние диалога в файл. |
Load(const int file_handle) | Загружает состояние диалога из файла. |
UpdateThemeColors(bool darkTheme) | Обновляет цвета темы (темные или светлые). |
CreateWhiteBorder(void) | Создает белую рамку для диалогового окна. |
CreateBackground(void) | Создает фон диалогового окна. |
CreateCaption(void) | Создает область подписи. |
CreateButtonClose(void) | Создает кнопку закрытия. |
CreateClientArea(void) | Создает клиентскую зону. |
OnClickCaption(void) | Обрабатывает событие щелчка по заголовку. |
OnClickButtonClose(void) | Обрабатывает событие нажатия кнопки закрытия. |
OnDialogDragStart(void) | Обрабатывает начало события перетаскивания диалогового окна. |
OnDialogDragProcess(void) | Управляет процессом перетаскивания диалогового окна. |
OnDialogDragEnd(void) | Обрабатывает событие перетаскивания конца диалогового окна. |
Давайте кратко рассмотрим один из основных классов, который мы используем в нашей программе ниже.
Добавление методов управления темами в (CDialog, CEdit и CButton)
Надеюсь, теперь у нас есть более четкое понимание методов, которые нам необходимо реализовать для переключения тем. Библиотека Dialog уже содержит необходимые основные функции, и нашим следующим шагом станет включение необходимых методов.
Методы управления темами CDialog:
CDialog:
Класс CDialog в MQL5 отвечает за создание и управление пользовательскими графическими диалоговыми окнами или панелями в платформе MetaTrader 5. Он позволяет разработчикам создавать диалоговые окна, содержащие компоненты пользовательского интерфейса, такие как заголовки, клиентские области, границы и кнопки закрытия. Класс обрабатывает такие взаимодействия с пользователем, как нажатие и перетаскивание диалогового окна, а также динамическое обновление его темы (например, переключение между светлой и темной темами). Кроме того, он предоставляет методы для сохранения и загрузки состояния диалогового окна, гарантируя сохранение его размера, положения и статуса минимизации. В диалоговое окно можно добавлять элементы управления, такие как кнопки и текстовые поля, что делает его универсальным инструментом для создания интерактивных и визуально привлекательных интерфейсов в торговых приложениях.
В классе CDialog мы ввели метод обработки динамических обновлений темы. Этот метод отвечает за обновление визуального вида диалога в зависимости от того, активна ли темная тема (darkTheme) или нет. Вот как этот метод реализован и как он связан с другими компонентами класса CDialog. Я объясню в два этапа. Однако вы можете пропустить первый этап, если не собираетесь определять цвета.
Этап 1: Определение цветов темы
Необходимо определить цвета, чтобы программа знала альтернативы при смене темы. В этой реализации наш метод использует конкретные определения цветов как для темных, так и для светлых тем. Это могут быть предопределенные константы или константы, передаваемые через параметры.
// 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;
Шаг 2: Метод обновления цветов темы
Эта функция проверяет, активна ли darkTheme (true или false), и применяет соответствующие цвета к ключевым компонентам: белая рамка (m_white_border) обновляется цветами фона и рамки; фон (m_background) изменяет цвета фона и рамки; заголовок (m_caption) изменяет цвета текста и фона строки заголовка; а клиентская область (m_client_area) применяет изменения цвета к клиентской области. Наконец, функция вызывает Redraw(), чтобы гарантировать визуальное применение новой темы без повторного создания объектов. Если вы перешли ко второму шагу, то выделенные определения цветов не будут работать, и цвет необходимо будет указать, например, ClrBlack или ClrBlue и так далее
//+------------------------------------------------------------------+ //| 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(); }
Управление темами класса CButton
Используя те же термины, что и выше, мы добавили методы SetTextColor, SetBackgroundColor и SetBorderColor к классу CButton. Эти методы позволяют нам задать цвета текста, фона и границы кнопки соответственно. Вот фрагмент кода, демонстрирующий реализацию методов.
//--- 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); }
Программа CButton по умолчанию из MQL5
//+------------------------------------------------------------------+ //| 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 со встроенным методом управления темами:
Обратите внимание на выделенный раздел.
//+------------------------------------------------------------------+ //| 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()); } //+------------------------------------------------------------------+
Управление темами класса CEdit
Это один из ключевых классов в нашем проекте, который управляет полем ввода сообщения. По умолчанию наша панель и ее компоненты имеют белый фон с черным текстом переднего плана. При нажатии кнопки переключения темы цвет переднего плана меняется на белый. Однако в процессе разработки я заметил, что цвет поля ввода остался неизменным, из-за чего он иногда сливался с текстом при переключении тем. Поэтому нам необходимо добавить метод в класс CEdit для обработки переключения тем и обеспечения соответствия поля ввода текста целям нашей темы.
В классе CEdit по умолчанию уже есть методы для установки цветов (OnSetColor, OnSetColorBackground и OnSetColorBorder). Мы можем использовать эти методы для обновления внешнего вида объекта CEdit при изменении темы. Мы применяем новые методы для переключения тем, например, добавляя методы SetTextColor, SetBackgroundColor и SetBorderColor в класс CEdit. Эти методы обновляют соответствующие цвета и вызывают существующие методы (OnSetColor, OnSetColorBackground, OnSetColorBorder) для применения изменений к объекту графика.
//+------------------------------------------------------------------+ //| 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()); }
Ниже мы рассмотрим неотредактированный исходный код класса CEdit и перейдем к представлению встроенной программы, расположенной сразу под ним.
CEdit по умолчанию из 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 с использованием метода управления темами:
Обратите внимание на выделенные разделы.
//+------------------------------------------------------------------+ //| 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()); } //+------------------------------------------------------------------+Мы успешно подготовили файлы управления для панели администратора и сейчас находимся ближе к завершению нашего проекта, чем когда-либо прежде. В следующем сегменте мы поправим код панели администратора для поддержки переключения тем в соответствии с последними разработками.
Настройка панели администратора для переключения тем.
Логически в нашем управлении темами можно выделить четыре ключевых направления.
- Функциональность переключения тем в нашей панели администратора должна быть сосредоточена вокруг булевой переменной darkTheme и функции UpdateThemeColors(). Вот как это работает:
bool darkTheme = false;
- Приведенный выше флаг определяет, является ли текущая тема темной или светлой. Переключается при нажатии toggleThemeButton, как показано ниже.
void OnToggleThemeButtonClick() { darkTheme = !darkTheme; UpdateThemeColors(); Print("Theme toggled: ", darkTheme ? "Dark" : "Light"); }
- Нажатие кнопки переключения темы вызывает эту функцию, которая переключает флаг darkTheme и впоследствии обновляет тему пользовательского интерфейса через UpdateThemeColors().
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(); }
Пользуясь флагом darkTheme, мы выбрали разные цвета для текста, фона кнопок, границ и фона. Цвета применяются к различным компонентам пользовательского интерфейса следующим образом:
- Текстовое поле (inputBox): Функции SetTextColor, SetBackgroundColor, и SetBorderColor используются для применения темы.
- Кнопки: Функция UpdateButtonTheme() вызывается для каждой кнопки, устанавливая цвет текста, цвет фона и цвет границы в соответствии с заданными параметрами.
- Счетчик символов: напрямую устанавливает свой цвет при нажатии кнопки темы.
//Theme button application void UpdateButtonTheme(CButton &button, color textColor, color bgColor, color borderColor) { button.SetTextColor(textColor); button.SetBackgroundColor(bgColor); button.SetBorderColor(borderColor); }
Мы использовали вспомогательную функцию выше, чтобы применить все соответствующие настройки цвета, связанные с темой, к любой кнопке. Это позволяет избавиться от повторяющегося кода и обеспечивает единообразие кнопок. Обобщив все фрагменты кода и интегрировав их в основную программу панели администратора, мы добились того, что все функции работают в соответствии с поставленной задачей.
Окончательный код и результаты
Вот окончательный вариант нашей программы с новыми функциями.
//+------------------------------------------------------------------+ //| 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; } }
Новая тема панели администратора
На рисунке ниже показаны все операции, выполняемые на панели, включая обработку ошибок. Невозможность отправить пользовательское сообщение может быть связана с отсутствующим или неправильным токеном Telegram-бота и идентификатором чата. Как видно на изображении, эти поля остались пустыми. Важно убедиться, что эти учетные данные введены правильно, поскольку они имеют решающее значение для работы. Сохраните эти учетные данные в надежном месте, чтобы предотвратить несанкционированный доступ.
Логи на вкладке "Эксперты"
Заключение
Статья знаменует собой еще одну веху в развитии нашей торговой панели администратора. Мы успешно интегрировали алгоритмы управления темами в существующие классы, не заметив при этом никаких проблем с производительностью, влияющих на другие функции платформы, которые используют те же библиотеки. Эти достижения предназначены в первую очередь для учебных и исследовательских целей. Тем не менее, изменение классов и интеграция новых методов могут иметь положительный эффект, но они также несут в себе риск нежелательных результатов, если не реализованы правильно. Наш проект стал более сложным, интегрируя функционал Telegram и расширенные возможности визуализации.
Я доволен прогрессом и надеюсь, что вы получили ценную информацию при работе с файлами библиотеки в MQL5. Можно достичь еще больших результатов, используя некоторые подходы, использованные в этом проекте. Ниже я прикрепил измененные исходные файлы. Обратите внимание, что функция переключения тем зависит от наличия этих библиотечных классов. Если у вас возникнут какие-либо проблемы, переустановите MetaTrader 5 для восстановления системных файлов и сброса классов в состояние по умолчанию.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16045
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования