使用MQL5轻松创建图形面板·进阶篇
🛠️

使用MQL5轻松创建图形面板·进阶篇

(2/3)·从标识认知到两种实现路线,搞懂面板类如何替你省下重复造轮子的时间

实战向 第 2/3 篇
很多交易者装了第三方面板却不懂底层结构,一旦界面卡死就只能干瞪眼。新手开发者常从头硬写所有控件,耗掉几天却连按钮回调都没理顺。先认清面板到底是什么、有哪几条构建路线,比盲目抄代码更省命。

「面板交互的事件分发逻辑」

在 MT5 图表面板上做手动下单工具,核心是把图表事件路由到正确的处理函数。下面这段初始化与 OnChartEvent 骨架,定义了卖按钮纵坐标、三个对象名(文本框 txttVol、买按钮 buyBtn、卖按钮 sellBtn)以及默认手数 0.01。 初始化时先调用 createPanel() 画出控件,随后用 ObjectDelete(0,...) 按名字清理旧对象,避免重复加载时残留。手数变量 lotSize 设为 double 型 0.01,是后续开仓函数的传入值。 OnChartEvent 里分两条路:若 id 为 CHARTEVENT_OBJECT_ENDEDIT 且 sparam 等于 txtName,说明交易者在文本框改了手数,先用 ObjectGetString 取回文本交给 setLot() 解析,再把文本框重设回 lotSize 的字符串形式。若 id 为 CHARTEVENT_OBJECT_CLICK,则按 sparam 判断点的是 buyBtn 还是 sellBtn:命中买按钮就把按钮状态置 false 并调 openTrade(ORDER_TYPE_BUY, lotSize);命中卖按钮同样复位状态,调 openTrade 开空。外汇与贵金属保证金交易杠杆高,面板一键下单可能迅速放大亏损,实盘前务必在策略测试器用 0.01 手验一遍事件触发。 把这段代码贴进 EA 的 OnChartEvent,你能在 MT5 里点按钮即触发对应 order 调用;若点击无反应,优先检查对象名字符串是否与 createPanel 内绘制时完全一致。

MQL5 / C++
const class="type">int sellY=txtY+ySpace+btnHeight;
const class="type">class="kw">string txtName="txttVol";
const class="type">class="kw">string buyName="buyBtn";
const class="type">class="kw">string sellName="sellBtn";
class="type">class="kw">double lotSize=class="num">0.01;
  createPanel();
  ObjectDelete(class="num">0,txtName);
  ObjectDelete(class="num">0,buyName);
  ObjectDelete(class="num">0,sellName);
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Interaction function                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnChartEvent(const class="type">int id, const class="type">long &lparam, const class="type">class="kw">double &dparam, const class="type">class="kw">string &sparam)
  {
class=class="str">"cmt">//--- If the event id is equal to the end of text editing in the panel and the class="type">class="kw">string type event is equal to the text name
   if(id==CHARTEVENT_OBJECT_ENDEDIT && sparam==txtName)
     {
      class=class="str">"cmt">//--- lotTxt class="type">class="kw">string variable will be equal to the returned class="kw">property value by using the ObjectGetString function
      class="type">class="kw">string lotTxt=ObjectGetString(class="num">0, txtName, OBJPROP_TEXT);
      class=class="str">"cmt">//--- call setLot function that we will create later with the lotTxt value
      setLot(lotTxt);
      class=class="str">"cmt">//Setting the class="kw">property value by using the ObjectSetString
      ObjectSetString(class="num">0, txtName, OBJPROP_TEXT, class="type">class="kw">string(lotSize));
      class=class="str">"cmt">//--- Use class="kw">return
      class="kw">return;
     }
class=class="str">"cmt">//--- If the event id is equal to the object click to check if we click the buy button
   else
    if(id==CHARTEVENT_OBJECT_CLICK)
      {
      class=class="str">"cmt">//We will check if the class="type">class="kw">string param is equal to buyname
      if(sparam==buyName)
        {
         class=class="str">"cmt">//--- Setting the value of the class="kw">property by using the ObjectSetInteger
         ObjectSetInteger(class="num">0, buyName, OBJPROP_STATE, class="kw">false);
         class=class="str">"cmt">//Calling the created openTrade to open a buy order.
         openTrade(ORDER_TYPE_BUY, lotSize);
         class=class="str">"cmt">//--- Use class="kw">return
         class="kw">return;
        }
      class=class="str">"cmt">//--- If the event id is equal to the object click to check if we click the sell button
      class=class="str">"cmt">//--- We will check if the class="type">class="kw">string param is equal to sellname
      else
       if(sparam==sellName)
         {
          class=class="str">"cmt">//--- Setting the value of the class="kw">property by using the ObjectSetInteger
          ObjectSetInteger(class="num">0, sellName, OBJPROP_STATE, class="kw">false);
          class=class="str">"cmt">//Calling the created openTrade to open a sell order

面板重建时先清旧对象再画编辑框

在 MT5 脚本里动态刷新交易面板,第一步必须是清场。createPanel() 开头连续调用 ObjectDelete(0, txtName)、ObjectDelete(0, buyName)、ObjectDelete(0, sellName),把上一轮残留的文本框和按钮对象从图表 0(当前图表)删掉,否则同名的 Edit 对象会叠加且属性不更新。 清完之后才调用 EditCreate 重画。注意它的第一个参数是 chart_ID = 0,表示绑定当前图表主窗口(sub_window 也填 0);坐标用 txtX / txtY 变量传,宽高用 txtWidth / txtHeight,这样面板位置可以随锚点函数 panelLoc 切换左上、右下等角落。 编辑框里显示的文本是 string(lotSize),也就是把手数变量实时转成字符串画上去;字体写死 "Arial"、字号 10、ALIGN_LEFT 左对齐,背景白、文字和边框黑。read_only 传 false 意味着这个框允许交易者直接改手数,改完回车就能驱动后面的 openTrade 逻辑。外汇和贵金属杠杆高,面板改手数后下单前务必人工核对,滑点和重报价可能导致实际成交手数与输入不符。

MQL5 / C++
class="type">void createPanel()
  {
class=class="str">"cmt">//--- Delete objects of txtName, buyName, and sellName
   ObjectDelete(class="num">0, txtName);
   ObjectDelete(class="num">0, buyName);
   ObjectDelete(class="num">0, sellName);
class=class="str">"cmt">//--- calling the EditCreate function
   EditCreate(               class=class="str">"cmt">// Parameters:
               class="num">0,                class=class="str">"cmt">// const class="type">long (chart_ID): to specify the chart&class="macro">#x27;s ID, we will use(class="num">0).
               txtName,           class=class="str">"cmt">// const class="type">class="kw">string (name): to specify the button name,  we will use(txtName)
               class="num">0,                class=class="str">"cmt">// const class="type">int (sub_window): to specify the subwindow index, we will use(class="num">0) for the main window
               txtX,             class=class="str">"cmt">// const class="type">int (x): to specify the X coordinate, we will use(txtX)
               txtY,             class=class="str">"cmt">// const class="type">int (y): to specify the Y coordinate, we will use(txtY)
               txtWidth,         class=class="str">"cmt">// const class="type">int (width):to specify the button width, we will use(txtWidth)
               txtHeight,        class=class="str">"cmt">// const class="type">int (height): to specify the button height, we will use(txtHeight)
               class="type">class="kw">string(lotSize),  class=class="str">"cmt">// const class="type">class="kw">string (text): to specify the text, we will use(lotSize)
               "Arial",          class=class="str">"cmt">// const class="type">class="kw">string (font): to specify the font, we will use "Arial"
               class="num">10,               class=class="str">"cmt">// const class="type">int (font_size): to specify the font size, we will use(class="num">10)
               ALIGN_LEFT,       class=class="str">"cmt">// const ENUM_ALIGN_MODE(align_mode): to specify the position of text, we will use(ALIGN_LEFT)
               class="kw">false,            class=class="str">"cmt">// const class="type">bool (read_only=class="kw">false): to specify the ability to edit, we will be(class="kw">false)
               panelLoc,         class=class="str">"cmt">// const ENUM_BASE_CORNER(corner): to specify the chart corner for anchoring, we will call panelLoc function
               clrBlack,         class=class="str">"cmt">// const class="type">color (clr): to specify the text class="type">color, we will specify clrBlack
               clrWhite,         class=class="str">"cmt">// const class="type">color (back_clr): to specify the background class="type">color, we will specify clrWhite
               clrBlack,         class=class="str">"cmt">// const class="type">color (border_clr): to specify the border class="type">color, we will specify clrBlack
               class="kw">false             class=class="str">"cmt">// const class="type">bool (back=class="kw">false): in the background, we will set class="kw">false

◍ 给买卖按钮传参的实盘写法

在 MT5 面板里画可点击的 Buy / Sell 按钮,核心就是反复调用 ButtonCreate,把坐标、尺寸、配色和锚定角一次性喂进去。下面这段是针对 buy 按钮的实际传参,sell 按钮只是把名字、坐标和背景色换掉,结构完全一致。 注意 chart_ID 用 0 代表当前图表,sub_window 用 0 锁死主窗口,z_order 也填 0——这意味着鼠标点击优先级走默认层,不会盖住 K 线交互。字体写死 Arial、字号 10,按钮文字色 clrBlack、背景 clrGreen,边框 clrBlack,state 与 back / selection / hidden 全为 false,保证按钮常态可见且不被误移动。 外汇与贵金属波动剧烈,这类一键下单面板只解决「点得准」,不解决「该不该点」,实盘前务必在策略测试器里先跑通事件回调。

MQL5 / C++
   ButtonCreate(               class=class="str">"cmt">// Parameters:
      class="num">0,                      class=class="str">"cmt">// const class="type">long (chart_ID): to specify the chart&class="macro">#x27;s ID, we will use(class="num">0)
      buyName,                class=class="str">"cmt">// const class="type">class="kw">string (name): to specify the button name, we will use(buyName) for the buy button
      class="num">0,                      class=class="str">"cmt">// const class="type">int (sub_window): to specify the subwindow index, we will use(class="num">0) for the main window
      buyX,                   class=class="str">"cmt">// const class="type">int (x): to specify the X coordinate, we will use(buyX) for buy
      buyY,                   class=class="str">"cmt">// const class="type">int (y): to specify the Y coordinate, we will use(buyY) for buy
      btnWidth,               class=class="str">"cmt">// const class="type">int (width): to specify the button width, we will use(btnWidth) for buy
      btnHeight,              class=class="str">"cmt">// const class="type">int (height): to specify the button height, we will use(btnHeight) for buy
      panelLoc,               class=class="str">"cmt">// const ENUM_BASE_CORNER(corner): to specify the chart corner for anchoring, we will call panelLoc function for buy button
      "Buy",                  class=class="str">"cmt">// const class="type">class="kw">string (text): to specify the text, we will use("Buy") for the buy button
      "Arial",                class=class="str">"cmt">// const class="type">class="kw">string (font): to specify the font, we will use "Arial"
      class="num">10,                     class=class="str">"cmt">// const class="type">int (font_size): to specify the font size, we will use(class="num">10)
      clrBlack,               class=class="str">"cmt">// const class="type">color (clr): to specify the text class="type">color, we will specify clrBlack
      clrGreen,               class=class="str">"cmt">// const class="type">color (back_clr): to specify the background class="type">color, we will specify clrGreen for the buy button
      clrBlack,               class=class="str">"cmt">// const class="type">color (border_clr): to specify the border class="type">color, we will specify clrBlack
      class="kw">false,                  class=class="str">"cmt">// const class="type">bool (state): to specify if the object is pressed or released, we will specify class="kw">false
      class="kw">false,                  class=class="str">"cmt">// const class="type">bool (back=class="kw">false): in the background, we will set class="kw">false
      class="kw">false,                  class=class="str">"cmt">// const class="type">bool (selection=class="kw">false): highlight to move, we will set class="kw">false
      class="kw">false,                  class=class="str">"cmt">// const class="type">bool (hidden): hidden in the object list, we will set class="kw">false
      class="num">0);                     class=class="str">"cmt">// const class="type">long (z_order=class="num">0): priority for mouse click, we will use(class="num">0) for buy button

「用 ButtonCreate 钉死 Sell 按钮的锚点与配色」

在 MT5 面板里挂一个可点击的卖出按钮,核心就是 ButtonCreate 这一串参数。图表 ID 传 0 代表当前图表,子窗口传 0 锁定主图,坐标 sellX / sellY 配合 panelLoc 决定它贴在左上还是右下角。 下面这段是创建卖出按钮的实际调用,逐行拆开看每个槽位在控什么: ButtonCreate( 0, // 图表 ID:0 即当前活跃图表 sellName, // 按钮对象名:用 sellName 变量区分多按钮 0, // 子窗口序号:0 为主图表窗口 sellX, // X 坐标:卖出按钮的水平位置 sellY, // Y 坐标:卖出按钮的垂直位置 btnWidth, // 按钮宽度像素 btnHeight, // 按钮高度像素 panelLoc, // 锚定角:由 panelLoc 函数返回 ENUM_BASE_CORNER "Sell", // 按钮文字:写死 "Sell" "Arial", // 字体:Arial 10, // 字号:10 clrBlack, // 文字色:黑 clrRed, // 背景色:红,卖单视觉警示 clrBlack, // 边框色:黑 false, // 初始状态:未按下 false, // 不放背景层 false, // 不允许选中拖动 false, // 对象列表里可见

  • ; // 鼠标点击优先级:0 为普通层

setLot 这段虽小但容易漏判:StringToDouble 转手数后若小于 0 直接 Print 报错并返回,不改写 lotSize。外汇与贵金属杠杆高,手数校验失败若默默继续,可能挂出非预期仓位,实盘前务必在策略测试器里点一下面板输负值验证分支。

MQL5 / C++
ButtonCreate(
  class="num">0,
  sellName,
  class="num">0,
  sellX,
  sellY,
  btnWidth,
  btnHeight,
  panelLoc,
  "Sell",
  "Arial",
  class="num">10,
  clrBlack,
  clrRed,
  clrBlack,
  class="kw">false,
  class="kw">false,
  class="kw">false,
  class="kw">false,
  class="num">0);
}
class="type">void setLot(class="type">class="kw">string lotTxt)
  {
   class="type">class="kw">double newLot=StringToDouble(lotTxt);
   if(newLot<class="num">0)
     {
      Print("Invaid Volume Specified");
      class="kw">return;
     }
   lotSize=newLot;
  }

用 OBJ_EDIT 在图表上落一个可编辑框

想在 MT5 图表上塞一个能手动改字的输入框,核心就是 OBJ_EDIT 对象。下面这个函数把坐标、尺寸、字体、对齐方式全参数化了,默认藏在背景层(hidden=true)且不参与鼠标选中,适合做内部状态显示或低调的交互控件。 函数头里 width 默认 50、height 默认 18、font_size 默认 10,这组数值在 1920×1080 屏上刚好是一行 Arial 小字的紧凑占位;若你做黄金 1 分钟图的悬浮标签,把 height 提到 22 可能更不容易挤字。 代码前半段先 ResetLastError() 清掉旧错误码,再用 ObjectCreate 以 (0,0) 为临时锚点建对象——注意 OBJ_EDIT 的创建不依赖时间/价格坐标,x、y 后面要靠 ObjectSetInteger 单独推。外汇与贵金属波动剧烈,这类图形对象仅作辅助,实盘仍属高风险。

MQL5 / C++
class="type">bool EditCreate(const class="type">long          chart_ID=class="num">0,
                  const class="type">class="kw">string        name="Edit",
                  const class="type">int           sub_window=class="num">0,
                  const class="type">int           x=class="num">0,
                  const class="type">int           y=class="num">0,
                  const class="type">int           width=class="num">50,
                  const class="type">int           height=class="num">18,
                  const class="type">class="kw">string        text="Text",
                  const class="type">class="kw">string        font="Arial",
                  const class="type">int           font_size=class="num">10,
                  const ENUM_ALIGN_MODE  align=ALIGN_CENTER,
                  const class="type">bool          read_only=class="kw">false,
                  const ENUM_BASE_CORNER corner=CORNER_LEFT_UPPER,
                  const class="type">color         clr=clrBlack,
                  const class="type">color         back_clr=clrWhite,
                  const class="type">color         border_clr=clrNONE,
                  const class="type">bool          back=class="kw">false,
                  const class="type">bool          selection=class="kw">false,
                  const class="type">bool          hidden=true,
                  const class="type">long          z_order=class="num">0)
  {
class=class="str">"cmt">//--- Reset the error value by using ResetLastError()
   ResetLastError();
class=class="str">"cmt">//--- Create an edit field
   if(!ObjectCreate(chart_ID, name, OBJ_EDIT, sub_window, class="num">0, class="num">0))
     {
把界面诊断交给小布盯盘
这些面板类的运行逻辑和常见报错模式,小布盯盘的 AIGC 已内置诊断,打开对应品种页即可看到控件状态提示,你专注策略而非调界面。

常见问题

面板可集成下单、平仓、账户信息展示等控件,点击即可执行,倾向减少在菜单间切换造成的分心,但外汇贵金属波动剧烈仍属高风险。
目前小布盯盘侧重盘面诊断与提醒,不输出完整EA源码;但你能用它核对自写面板的品种上下文是否异常。
坐标计算、事件循环、重绘都要手写,维护成本随控件增多指数上升,可能更适合练手而非实盘。
面板常驻悬浮用于持续交互,对话框多为弹窗式确认或输入;按交互频率选,避免误用导致终端卡顿。