
在MQL5中创建交易管理员面板(第三部分):扩展内置类以进行主题管理(II)
内容:
- 引言
- 理解MQL5中的类
- 向(CDialog, CEdit, and CButton)添加主题管理方法
- 主题管理类CButton
- 主题管理类CEdit
- 为管理员面板调整主题切换功能
- 最终的代码和结果
- 结论
引言
我们可以修改并为MQL5创建新的类库。然而,由于内置库由平台共享,我们对这些文件所做的任何修改,都可能对当前平台的功能产生正面或负面影响。在最近文章中,我们简要讨论了如何编辑根对话框类颜色,以控制我们面板的外观。尽管主题切换按钮成功地改变了文本颜色,但它并没有改变面板皮肤或按钮背景颜色。
通过研究,我们终于确定了将主题更改功能安全地整合到现有类中的方法。在成功实现这些更改后,我们调整了管理员面板算法,使其与新整合的功能保持一致。
主题切换成功
今天的讨论重点是我们为实现右侧显示的美观面板所采取的步骤。所展示的主题颜色是基于我在开发过程中对颜色选择的看法;它们可以在代码中进行优化,以适应其他用户的偏好,允许您尝试不同的颜色,以找到与您产生共鸣的颜色。重要的是要突出我们程序的关键组成部分,这些部分有助于面板的整体功能。
我将列出它们:
- 文本颜色
- 按钮皮肤颜色
- 边框
- 背景颜色
本质上,这些是我们程序中最显而易见的特征。当我们触发主题更改时,每个组件都必须通过更改其显示属性来响应,以展示代码中定义的所需颜色。在本次讨论结束时,我们旨在赋予您在处理界面时修改和扩展现有类所需的技能,正如本项目所展示的那样。
了解MQL5中的类。
为了确保专家和新手都能跟上,我想先让大家熟悉MQL5中使用的类的概念。以下是定义和关键概念,将帮助我们理解类在这个编程环境中的功能。
类:
类是MQL5中面向对象编程(OOP)的基础,允许开发人员将相关的变量(属性)和函数(方法)组合成一个单元,以在程序中表示复杂的概念和行为。
将一个类分解为两个部分:
- 属性:存储类对象的状态或数据的变量。
- 方法:定义类对象的行为或动作的函数。
类的主要特征概述:
- 封装是指将数据(变量)和操作这些数据的方法(函数)捆绑在一起,确保它们受到保护,防止外部访问和滥用。
- 继承允许一个类从另一个类继承属性和方法,促进代码重用并创建层次结构。
- 多态性允许方法重写,允许子类为其父类中已经定义的方法提供特定的实现。
- 抽象通过仅关注相关数据和方法,隐藏不必要的细节,简化复杂系统的建模。
定位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, and CButton)添加主题管理方法
现在,我相信我们对实现主题切换目标所需的方法有了更清晰的理解。对话框库已经包含了所需的基本功能,我们下一步将是整合必要的方法。
CDialog Theme Management Methods:
CDialog:
在MQL5中,CDialog类负责在MetaTrader 5平台内创建和管理自定义图形对话框窗口或面板。它允许开发人员构建包含标题、客户区域、边框和关闭按钮等UI组件的对话框。该类处理用户交互,如点击和拖动对话框,以及动态更新其主题(例如,在深色和浅色模式之间切换)。此外,它还提供方法来保存和加载对话框的状态,确保其大小、位置和最小化状态得以保留。可以将按钮和文本字段等控件添加到对话框中,使其成为构建交易应用程序中交互式和视觉吸引力界面的多功能工具。
在CDialog类中,我们引入了一个用于处理动态主题更新的方法。该方法负责根据深色主题是否激活来更新对话框的视觉外观。下面是如何整合该方法以及它如何与其他CDialog类组件结合的说明。我将分两步进行解释。然而,如果你不打算定义颜色,可以跳过第一步。
第一步:定义主题颜色
需要定义颜色,以便程序在调用主题更改时知道替代方案。在此实现中,我们的方法为深色和浅色主题使用特定的颜色定义。这些可以是预定义的常量,也可以通过参数传递。
// 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;
第二步:更新主题颜色方法
该函数检查深色主题是否激活(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类的主题管理
用上述相同方式,我们在 CButton 类中添加了 SetTextColor、SetBackgroundColor 和 SetBorderColor 方法。这些方法分别允许我们设置按钮的文本、背景和边框颜色。以下是展示这些方法实现的代码片段。
//--- 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); }
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类:
请看高亮部分。
//+------------------------------------------------------------------+ //| 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 类源代码,并在下方分享整合后的程序代码。
MQL5中默认的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)); } 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()); } //+------------------------------------------------------------------+我们已经成功地为管理员面板准备好了控件的头文件,我们比以往任何时候都更接近完成我们的项目。在下一部分中,我们将通过调整管理员面板EA的代码以支持主题切换功能,从而完善我们的项目,使其与最新的开发进展保持一致。
为管理员面板调整主题切换功能。
在我们的主题管理中有四个逻辑上的关键点。
- The theme switching functionality in our Admin panel must be centered around the darkTheme boolean variable and the UpdateThemeColors() function. 以下是它如何运作的:
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机器人令牌和聊天 ID填写缺失或错误。如图所示,这些字段被留空了。确保这些认证信息输入正确非常重要,因为它们对于后续操作至关重要。请记住保护好这些认证信息,以防止未经授权的访问。
EA的日志
结论
这是我们交易系统管理面板开发过程中的又一里程碑。我们已经成功地将主题管理算法整合到现有类中,并且没有观察到对依赖相同库的其他平台功能造成任何性能影响。这些改进主要是为了学习和研究目的。然而,修改类和整合新方法可能会产生积极影响,但如果实施不当,也可能会带来不良后果的风险。我们的项目现在变得更加复杂,集成了Telegram功能和高级可视化特性。
我对我们的进展感到满意,并希望您从使用 MQL5 库文件的工作中获得宝贵的洞见。使用本项目中所采用的一些方法,仍然可以实现更多功能。我已将修改后的源文件附在下方。请注意,主题切换功能依赖于这些库类的存在。如果您遇到任何问题,请考虑重新安装MetaTrader 5以恢复系统文件并将类重置为默认状态。
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/16045



