利用 MQL5 的交互式 GUI 改进您的交易图表(第 III 部分):简易可移动交易 GUI·进阶篇
🖱️

利用 MQL5 的交互式 GUI 改进您的交易图表(第 III 部分):简易可移动交易 GUI·进阶篇

(2/3)· 还在把按钮坐标写死在 EA 里?本篇用 .mqh 类把七个元素拆成可复用模块,让仪表板真正能拖着跑

含代码示例 第 2/3 篇
把交易面板直接画死在图表坐标上,改个手数框位置就得翻几百行代码。用类把标签、按钮、编辑框拆开封装,后续移动和复用都只是改几个参数。

用类封装MT5图表标签的生灭

在 MT5 里做自定义面板,第一步往往是把图表上的文字标签管起来。下面这段代码用 C++ 风格的类把标签的创建和销毁收进同一个对象,避免在 OnInit / OnDeinit 里散落一堆 ObjectCreate 调用。 RectangleLabel TitleBar 与 MainDashboardBody 是两个实例,前者尺寸 200×20 定位在 (100,100),后者 200×100 定位在 (100,119),两者都设了 BORDER_FLAT 平边。初始化末尾调 ChartRedraw(0) 强制重绘,EA 卸载时 OnDeinit 里先 Destroy 主体再 Destroy 标题栏,顺序反过来也可能泄漏对象。 Label 类只留了私有名和几个内联方法:Create 负责建对象,Destroy 直接 ObjectDelete(0,_name) 删掉,SetTextColor / SetText 分别改颜色和文字。注意这里 _name 是私有成员,Create 传进来的 name 必须写进 _name 才能真正删对,原片段没展示赋值,复制时容易漏。 外汇与贵金属波动剧烈,这类 GUI 对象不参与报价,但占用终端资源;EA 频繁重载时若 Destroy 不全,图表上可能残留幽灵标签,建议开 MT5 用脚本跑一遍 OnInit→OnDeinit 看对象树。

MQL5 / C++
RectangleLabel TitleBar; class=class="str">"cmt">// Declaration of a TitleBar object
RectangleLabel MainDashboardBody; class=class="str">"cmt">// Declaration of a MainDashboardBody object
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
   TitleBar.Create("TitleBar", class="num">100, class="num">100, class="num">200, class="num">20); class=class="str">"cmt">// Creating the TitleBar with specified dimensions
   TitleBar.SetBorderType(BORDER_FLAT); class=class="str">"cmt">// Setting the border type of TitleBar to be flat
   MainDashboardBody.Create("MainDashboardBody", class="num">100, class="num">119, class="num">200, class="num">100); class=class="str">"cmt">// Creating the MainDashboardBody with specified dimensions
   MainDashboardBody.SetBorderType(BORDER_FLAT); class=class="str">"cmt">// Setting the border type of MainDashboardBody to be flat
   ChartRedraw(class="num">0); class=class="str">"cmt">// Redrawing the chart to reflect changes
   class="kw">return(INIT_SUCCEEDED); class=class="str">"cmt">// Indicating successful initialization
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason)
  {
   MainDashboardBody.Destroy(); class=class="str">"cmt">// Destroying the MainDashboardBody object
   TitleBar.Destroy(); class=class="str">"cmt">// Destroying the TitleBar object
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Label class definition                                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class Label
  {
class="kw">private:
   class="type">class="kw">string          _name; class=class="str">"cmt">// Name of the label
class="kw">public:
                  Label(class="type">void); class=class="str">"cmt">// Constructor
                 ~Label(class="type">void); class=class="str">"cmt">// Destructor

   class="type">void            Create(class="type">class="kw">string name, class="type">int xDis, class="type">int yDis); class=class="str">"cmt">// Method to create a label
   class="type">void            Destroy() {ObjectDelete(class="num">0, _name);} class=class="str">"cmt">// Method to destroy a label
   class="type">void            SetTextColor(class="type">class="kw">color col) {ObjectSetInteger(class="num">0, _name, OBJPROP_COLOR, col);} class=class="str">"cmt">// Method to set the text class="type">class="kw">color
   class="type">void            SetText(class="type">class="kw">string text) {ObjectSetString(class="num">0, _name, OBJPROP_TEXT, text);} class=class="str">"cmt">// Method to set the text content

◍ 给图表挂上可复用的文字标签类

在 MT5 里做自定义面板,最轻量的起点就是 OBJ_LABEL 对象。下面这段把标签的取文本、字号、字体封装成类方法,调用层不用再反复写 ObjectGetString / ObjectSetInteger。 GetText() 用 ObjectGetString(0, _name, OBJPROP_TEXT) 回读标签内容;SetFontSize(int) 与 SetFont(string) 分别改 OBJPROP_FONTSIZE 和 OBJPROP_FONT。注意构造和析构函数体都是空的,资源释放依赖图表对象自动回收,若脚本重复运行要先 ObjectDelete 同名对象避免堆叠。 Create 方法里 ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0) 的第三参时间轴、第四五参坐标都填 0,因为标签走的是 XDISTANCE / YDISTANCE 像素偏移而非价格坐标——实测在 1920 宽屏上 xDis=100 大约距左缘 5.2% 屏宽。 OnInit 中 TitleBar 与 MainDashboardBody 的 y 坐标差 19(100 与 119),正好留出 20 像素高的标题条下边界;外汇与贵金属图表叠加这类自绘元素时,需留意其可能遮挡右侧报价列,属高风险界面的视觉干扰。

MQL5 / C++
class="type">class="kw">string GetText() {class="kw">return ObjectGetString(class="num">0, _name, OBJPROP_TEXT);} class=class="str">"cmt">// Method to retrieve the text content
class="type">void SetFontSize(class="type">int fontSize) {ObjectSetInteger(class="num">0, _name, OBJPROP_FONTSIZE, fontSize);} class=class="str">"cmt">// Method to set the font size
class="type">void SetFont(class="type">class="kw">string fontName) {ObjectSetString(class="num">0, _name, OBJPROP_FONT, fontName);} class=class="str">"cmt">// Method to set the font name
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Constructor                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
Label::Label(class="type">void)
  {
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Destructor                                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
Label::~Label(class="type">void)
  {
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Method to create a label object                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Label::Create(class="type">class="kw">string name, class="type">int xDis, class="type">int yDis)
  {
   class=class="str">"cmt">// Code to create label object, set its position, and assign its name
   ObjectCreate(class="num">0, name, OBJ_LABEL, class="num">0, class="num">0, class="num">0);
   ObjectSetInteger(class="num">0, name, OBJPROP_XDISTANCE, xDis);
   ObjectSetInteger(class="num">0, name, OBJPROP_YDISTANCE, yDis);
   _name = name;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#include "RectangleLabel.mqh" class=class="str">"cmt">// Including the RectangleLabel class definition
RectangleLabel TitleBar; class=class="str">"cmt">// Declaration of a TitleBar object
RectangleLabel MainDashboardBody; class=class="str">"cmt">// Declaration of a MainDashboardBody object
class="macro">#include "Label.mqh" class=class="str">"cmt">// Including the Label class definition
Label TitleText; class=class="str">"cmt">// Declaration of a Label object
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
   TitleBar.Create("TitleBar", class="num">100, class="num">100, class="num">200, class="num">20); class=class="str">"cmt">// Creating the TitleBar with specified dimensions
   TitleBar.SetBorderType(BORDER_FLAT); class=class="str">"cmt">// Setting the border type of TitleBar to be flat
   MainDashboardBody.Create("MainDashboardBody", class="num">100, class="num">119, class="num">200, class="num">100); class=class="str">"cmt">// Creating the MainDashboardBody with specified dimensions

「EA面板对象的创建与销毁节奏」

在 MT5 的 EA 初始化函数里,先通过 RectangleLabel 和 Label 的 Create 方法把面板控件实例化,坐标和尺寸直接写死即可。上面这段把 TitleBar 放在 (100,100) 宽200高20,MainDashboardBody 放在 (100,119) 宽200高100,两个都设了 BORDER_FLAT,视觉上就是平边矩形不凸出。 TitleText 在 (110,101) 写「Simple Trading EA V1.0」,字号10、黑色;LotSizeText 在 (110,140) 写「Lot Size:」,字号12、黑色。注意 LotSizeText 的坐标 y=140 落进了 MainDashboardBody 的区域内(119~219),说明文字层是叠在底板之上的,实际跑起来不会遮挡。 初始化末尾调 ChartRedraw(0) 强制重绘,返回 INIT_SUCCEEDED 才算挂 EA 成功。OnDeinit 里三个 Destroy 必须一一对应,漏掉任何一个都可能让图表残留旧控件。 开 MT5 把这段塞进 OnInit / OnDeinit 验证:若改了 TitleBar 的 y 从100到90,标题栏会和主面板重叠 29 像素,界面会显脏,调坐标时按 100/119 这种 19 像素落差留白更稳。

MQL5 / C++
MainDashboardBody.SetBorderType(BORDER_FLAT); class=class="str">"cmt">// 设置主面板边框为平边

TitleText.Create("TitleText", class="num">110, class="num">101); class=class="str">"cmt">// 在(class="num">110,class="num">101)创建标题文字
TitleText.SetText("Simple Trading EA V1.class="num">0"); class=class="str">"cmt">// 文字内容
TitleText.SetFontSize(class="num">10); class=class="str">"cmt">// 字号10
TitleText.SetTextColor(clrBlack); class=class="str">"cmt">// 黑色

ChartRedraw(class="num">0); class=class="str">"cmt">// 重绘图表
class="kw">return(INIT_SUCCEEDED); class=class="str">"cmt">// 初始化成功

class="type">void OnDeinit(const class="type">int reason)
  {
   MainDashboardBody.Destroy(); class=class="str">"cmt">// 销毁主面板
   TitleBar.Destroy(); class=class="str">"cmt">// 销毁标题栏
   TitleText.Destroy(); class=class="str">"cmt">// 销毁标题文字
  }

class="macro">#include "RectangleLabel.mqh"
RectangleLabel TitleBar;
RectangleLabel MainDashboardBody;
class="macro">#include "Label.mqh"
Label TitleText;
Label LotSizeText;

class="type">int OnInit()
  {
   TitleBar.Create("TitleBar", class="num">100, class="num">100, class="num">200, class="num">20); class=class="str">"cmt">// 标题栏x100 y100 宽200高20
   TitleBar.SetBorderType(BORDER_FLAT);
   MainDashboardBody.Create("MainDashboardBody", class="num">100, class="num">119, class="num">200, class="num">100); class=class="str">"cmt">// 主面板x100 y119 宽200高100
   MainDashboardBody.SetBorderType(BORDER_FLAT);

   TitleText.Create("TitleText", class="num">110, class="num">101);
   TitleText.SetText("Simple Trading EA V1.class="num">0");
   TitleText.SetFontSize(class="num">10);
   TitleText.SetTextColor(clrBlack);

   LotSizeText.Create("LotSizeText", class="num">110, class="num">140); class=class="str">"cmt">// 手数字段x110 y140
   LotSizeText.SetText("Lot Size:");
   LotSizeText.SetFontSize(class="num">12);
   LotSizeText.SetTextColor(clrBlack);

EA 退出时如何干净销毁图形对象

在 MT5 的 EA 生命周期里,OnDeinit 是释放资源的最后一道关口。上面这段代码在退出时依次调用 MainDashboardBody、TitleBar、TitleText、LotSizeText 的 Destroy 方法,把创建过的 OBJ_LABEL 类对象逐个从图表上删掉,避免重加载时残留旧标签。 ChartRedraw(0) 放在初始化收尾,是为了让新建的面板立即重绘出来;return(INIT_SUCCEEDED) 告诉终端初始化没问题。若跳过 OnDeinit 的销毁,切换周期时图表上可能叠出两套同名对象。 下面定义的 Edit 类把输入框封装成了可复用的控件:Create 按 xDis/yDis/xSize/ySize 定位,Destroy 直接 ObjectDelete(0,_name) 删对象。SetBorderColor、SetBGColor、SetTextColor 分别改边框、背景、文字色,全部走 ObjectSetInteger;SetText 与 GetText 用 ObjectSetString / ObjectGetString 读写 OBJPROP_TEXT。 实盘加载这类面板 EA 前,先在策略测试器用 0.1 手回测一遍 EURUSD 的 M15,确认 OnDeinit 被调用后对象数归零,外汇保证金交易杠杆高,误删或残留都可能干扰下单逻辑。

MQL5 / C++
  ChartRedraw(class="num">0); class=class="str">"cmt">// Redrawing the chart to reflect changes
  class="kw">return(INIT_SUCCEEDED); class=class="str">"cmt">// Indicating successful initialization
   }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason)
  {
    MainDashboardBody.Destroy(); class=class="str">"cmt">// Destroying the MainDashboardBody object
    TitleBar.Destroy(); class=class="str">"cmt">// Destroying the TitleBar object
    TitleText.Destroy(); class=class="str">"cmt">// Destroying the TitleText object
    LotSizeText.Destroy(); class=class="str">"cmt">// Destroying the LotSizeText object
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Edit class definition                                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class Edit
  {
class="kw">private:
    class="type">class="kw">string           _name; class=class="str">"cmt">// Name of the edit control
class="kw">public:
                     Edit(class="type">void); class=class="str">"cmt">// Constructor
                    ~Edit(class="type">void); class=class="str">"cmt">// Destructor

    class="type">void             Create(class="type">class="kw">string name, class="type">int xDis, class="type">int yDis, class="type">int xSize, class="type">int ySize); class=class="str">"cmt">// Method to create an edit control
    class="type">void             Destroy() {ObjectDelete(class="num">0, _name);} class=class="str">"cmt">// Method to destroy an edit control
    class="type">void             SetBorderColor(class="type">class="kw">color col) {ObjectSetInteger(class="num">0, _name, OBJPROP_BORDER_COLOR, col);} class=class="str">"cmt">// Method to set the border class="type">class="kw">color
    class="type">void             SetBGColor(class="type">class="kw">color col) {ObjectSetInteger(class="num">0, _name, OBJPROP_BGCOLOR, col);} class=class="str">"cmt">// Method to set the background class="type">class="kw">color
    class="type">void             SetTextColor(class="type">class="kw">color col) {ObjectSetInteger(class="num">0, _name, OBJPROP_COLOR, col);} class=class="str">"cmt">// Method to set the text class="type">class="kw">color
    class="type">void             SetText(class="type">class="kw">string text) {ObjectSetString(class="num">0, _name, OBJPROP_TEXT, text);} class=class="str">"cmt">// Method to set the text content
    class="type">class="kw">string           GetText() {class="kw">return ObjectGetString(class="num">0, _name, OBJPROP_TEXT);} class=class="str">"cmt">// Method to retrieve the text content
  };
class=class="str">"cmt">//+------------------------------------------------------------------+

◍ 在 MT5 图表上搭一个输入框控件

写一个可复用的编辑框类,第一步是把构造和析构留空,真正初始化交给 Create 方法。下面这段 MQL5 代码演示了 Edit 类如何用 ObjectCreate 在图表上生成一个 OBJ_EDIT 控件,并设定相对坐标与尺寸。 空构造与析构只是占位,避免对象生成时做多余动作;Create 里先以图表子窗口 0、时间 0、价格 0 创建对象,再用 ObjectSetInteger 把 XDISTANCE/YDISTANCE 和 XSIZE/YSIZE 逐个写入,最后把 name 存进成员变量 _name 供后续调用。 实际面板里,LotSize 编辑框往往和 RectangleLabel 做的标题栏、Label 做的文字并排。OnInit 中 TitleBar 放在 (100,100) 尺寸 200×20,MainDashboardBody 紧随其后在 (100,119) 尺寸 200×100,两者都用 BORDER_FLAT;标题文字字号设 10、内容写「Simple Trading EA V1.0」。打开 MT5 按这套坐标跑一遍,能直观看到控件层叠关系。 外汇与贵金属图表上叠加自绘 UI 属于高风险操作环境,控件坐标若和 K 线区域重叠会挡视线,参数需按自己屏幕 DPI 微调。

MQL5 / C++
class=class="str">"cmt">//| Constructor                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
Edit::Edit(class="type">void)
  {
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Destructor                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
Edit::~Edit(class="type">void)
  {
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Method to create an edit control object                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Edit::Create(class="type">class="kw">string name, class="type">int xDis, class="type">int yDis, class="type">int xSize, class="type">int ySize)
  {
    class=class="str">"cmt">// Code to create edit control object, set its position, size, and assign its name
    ObjectCreate(class="num">0, name, OBJ_EDIT, class="num">0, class="num">0, class="num">0);
    ObjectSetInteger(class="num">0, name, OBJPROP_XDISTANCE, xDis);
    ObjectSetInteger(class="num">0, name, OBJPROP_YDISTANCE, yDis);
    ObjectSetInteger(class="num">0, name, OBJPROP_XSIZE, xSize);
    ObjectSetInteger(class="num">0, name, OBJPROP_YSIZE, ySize);
    _name = name;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#include "RectangleLabel.mqh" class=class="str">"cmt">// Including the RectangleLabel class definition
RectangleLabel TitleBar; class=class="str">"cmt">// Declaration of a TitleBar object
RectangleLabel MainDashboardBody; class=class="str">"cmt">// Declaration of a MainDashboardBody object
class="macro">#include "Label.mqh" class=class="str">"cmt">// Including the Label class definition
Label TitleText; class=class="str">"cmt">// Declaration of a Label object
Label LotSizeText; class=class="str">"cmt">// Declaration of a LotSizeText object
class="macro">#include "Edit.mqh" class=class="str">"cmt">// Including the Edit class definition
Edit LotSize; class=class="str">"cmt">// Declaration of a LotSize object
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
    TitleBar.Create("TitleBar", class="num">100, class="num">100, class="num">200, class="num">20); class=class="str">"cmt">// Creating the TitleBar with specified dimensions
    TitleBar.SetBorderType(BORDER_FLAT); class=class="str">"cmt">// Setting the border type of TitleBar to be flat
    MainDashboardBody.Create("MainDashboardBody", class="num">100, class="num">119, class="num">200, class="num">100); class=class="str">"cmt">// Creating the MainDashboardBody with specified dimensions
    MainDashboardBody.SetBorderType(BORDER_FLAT); class=class="str">"cmt">// Setting the border type of MainDashboardBody to be flat
    
    TitleText.Create("TitleText", class="num">110, class="num">101); class=class="str">"cmt">// Creating the TitleText at(class="num">110,class="num">101)
    TitleText.SetText("Simple Trading EA V1.class="num">0"); class=class="str">"cmt">// Setting its text to "Simple Trading EA V1.class="num">0"
    TitleText.SetFontSize(class="num">10); class=class="str">"cmt">// Setting its font size to class="num">10

「面板对象的销毁与按钮类收尾」

初始化收尾阶段把标题文字、手数标签和输入框都摆到了固定坐标:LotSizeText 在 (110,140),LotSize 编辑框在 (220,140) 且宽 50 高 20,默认填 0.01、底色 clrWhiteSmoke。最后调 ChartRedraw(0) 强制重绘,返回 INIT_SUCCEEDED 才算 EA 加载成功。 退出时 OnDeinit 里挨个 Destroy 掉 MainDashboardBody、TitleBar、TitleText、LotSizeText、LotSize 五个对象,不清理的话切换周期可能留下残影控件。 后面跟了一个极简 Button 类,私有成员只有 _name 字符串,公有 Create 接收 name、xDis、yDis、xSize、ySize 五个参数去建对象;SetBorderColor 直接用 ObjectSetInteger 改 OBJPROP_BORDER_COLOR。这类封装让你在 MT5 里批量生成按钮时少写重复代码,复制去改坐标就能跑。

MQL5 / C++
TitleText.SetTextColor(clrBlack); class=class="str">"cmt">// Setting its text class="type">class="kw">color to clrBlack

LotSizeText.Create("LotSizeText", class="num">110, class="num">140); class=class="str">"cmt">// Creating the LotSizeText at(class="num">110,class="num">140)
LotSizeText.SetText("Lot Size:"); class=class="str">"cmt">// Setting its text to "Lot Size:"
LotSizeText.SetFontSize(class="num">12); class=class="str">"cmt">// Setting its font size to class="num">12
LotSizeText.SetTextColor(clrBlack); class=class="str">"cmt">// Setting its text class="type">class="kw">color to clrBlack

LotSize.Create("LotSize", class="num">220, class="num">140, class="num">50, class="num">20); class=class="str">"cmt">// Creating the LotSize with specified dimensions
LotSize.SetBorderColor(clrBlack); class=class="str">"cmt">// Setting its Border Color to clrBlack
LotSize.SetBGColor(clrWhiteSmoke); class=class="str">"cmt">// Setting its BG Color to clrWhiteSmoke
LotSize.SetText("class="num">0.01"); class=class="str">"cmt">// Setting its text to class="num">0.01
LotSize.SetTextColor(clrBlack); class=class="str">"cmt">// Setting its text class="type">class="kw">color to clrBlack

ChartRedraw(class="num">0); class=class="str">"cmt">// Redrawing the chart to reflect changes
class="kw">return(INIT_SUCCEEDED); class=class="str">"cmt">// Indicating successful initialization
 }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason)
  {
   MainDashboardBody.Destroy(); class=class="str">"cmt">// Destroying the MainDashboardBody object
   TitleBar.Destroy(); class=class="str">"cmt">// Destroying the TitleBar object
   TitleText.Destroy(); class=class="str">"cmt">// Destroying the TitleText object
   LotSizeText.Destroy(); class=class="str">"cmt">// Destroying the LotSizeText object
   LotSize.Destroy(); class=class="str">"cmt">// Destroying the LotSize object
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Button class definition                                           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class Button
  {
class="kw">private:
   class="type">class="kw">string          _name; class=class="str">"cmt">// Name of the button control
class="kw">public:
                  Button(class="type">void); class=class="str">"cmt">// Constructor
                 ~Button(class="type">void); class=class="str">"cmt">// Destructor

   class="type">void            Create(class="type">class="kw">string name, class="type">int xDis, class="type">int yDis, class="type">int xSize, class="type">int ySize); class=class="str">"cmt">// Method to create a button control
   class="type">void            SetBorderColor(class="type">class="kw">color col) {ObjectSetInteger(class="num">0, _name, OBJPROP_BORDER_COLOR, col);} class=class="str">"cmt">// Method to set the border class="type">class="kw">color
把重复劳动交给小布
这些 GUI 模块的样板代码小布盯盘的 AIGC 已内置,打开对应品种页即可看到生成好的面板骨架,你只调业务逻辑。

常见问题

Label 多用于静态文字,Rectangle Label 可设背景与边框、作为容器承载按钮和编辑框,更适合做可移动仪表板的主区域。
可以,小布内置的 AIGC 能按你指定的元素清单输出分文件 .mqh 类封装,省去手写坐标与事件绑定的重复工作。
拆分能让标签、按钮、编辑框各自成类,避免重复代码,也方便后续接入满级 EA 或指标时单独替换某个元素。
通常是记录鼠标按下时的偏移量,在 CHARTEVENT_MOUSE_MOVE 里按偏移重算各元素坐标并统一重绘,封装成方法后调用即可。