首页 / 交易学院 / 用 CChartObject 扩展 MQL5 图形控件:进度条、微调器、表格
用 CChartObject 扩展 MQL5 图形控件:进度条、微调器、表格
🧩

用 CChartObject 扩展 MQL5 图形控件:进度条、微调器、表格

MQL5 编程 难度 · 高阶 2013 13 分钟阅读
CChartObjectGUI 控件MQL5

为什么要从裸 ObjectCreate 迁移到 CChartObject

在上一篇用 GUI 做半自动 EA 之后,作者发现更复杂的指标和 EA 还需要进度条、数字微调框、表格这类组件。如果不碰标准库,这些只能靠 ObjectCreate 加一堆 ObjectSet* 字符串属性硬搭,繁琐且极易拼错。MQL5 的 OOP 让我们可以“继承 CChartObjectEdit 写自己的控件”:声明实例、调方法改属性,编辑器还能补全,代码既好记又快。

三个组件,都派生自 CChartObjectEdit

本文实施了三个派生类,全部继承自 CChartObjectEdit:CChartObjectProgressBar(进度条)、CChartObjectSpinner(带 +/− 的数字框)、CChartObjectEditTable(二维表格)。它们共用同一套路——在 Create 里先调基类建好 OBJ_EDIT 对象,再叠加自己的子对象与逻辑。理解一个,其余两个都是它的变体。

CChartObjectProgressBar:进度条

ProgressBar 的 Create(long chart_id, string name, int window, int X, int Y, int sizeX, int sizeY, int direction=0) 多了一个 direction 参数:当 direction!=0 表示竖向,构造函数会把 Y 改成 Y−sizeY,让条从下往上长。内部条 m_bar 是另一个 CChartObjectEdit,设成白底、不可选、只读。SetValue(int val) 时,横向按 stepSize = sizeX/(max−min) 重算 m_bar 的宽度,竖向则重算高度并调整 Y 锚点。Type() 固定返回 OBJ_EDIT,这样它仍是一个编辑框对象,只是被当成进度条用。

CChartObjectSpinner:带加减按钮的数字框

Spinner 在编辑框右侧叠两个 CChartObjectButton:上半高 m_up(文字“+”)、下半高 m_down(文字“−”)。Create 里还接了初值 val、步长 stepSize 和精度 precision(默认 8 位)。Inc()/Dec() 用 NormalizeDouble 按精度比较,越界就停在 [min,max],然后改 Description 显示新值。精度参数很关键——不直接用浮点比较,避免 0.1+0.1+0.1≠0.3 之类的显示抖动。

CChartObjectEditTable:二维动态对象数组表格

表格是最复杂的一个:用 CArrayObj 做“列数组里再套行编辑框”的二维动态结构,每个单元格命名为 name+i+":"+j 便于定位。Create(long chart_id, string name, int window, int rows, int cols, int startX, int startY, int sizeX, int sizeY, color Bg, int deltaX, int deltaY) 按行列和间距铺满单元格。SetText/GetText(row,col) 通过 array2D.At(col).At(row) 找到对应编辑框再读写。Delete() 要递归清掉列数组并释放内存,否则留下一堆孤立对象。

用 OnChartEvent 让 Spinner 真正动起来

让 Spinner 能响应点击靠 OnChartEvent:当 id==CHARTEVENT_OBJECT_CLICK 时,用 sparam 比对按钮名(如 spinner1_up / spinner1_down),命中就调对应 spinner 的 Inc()/Dec(),再把最新值写进某个标签的 Description 并 ChartRedraw()。这是标准库对象事件最典型的用法,也是把“静态控件”变成“可交互控件”的桥梁。

接入与几个坑

常见问题

MQL5 图表本身没有现成进度条、微调器,需要手动组合图形对象。封装成类后复用性更强。
CArrayObj 可以嵌套:每列是一个 CArrayObj,里面再放单元格对象。这样实现行和列的动态增删。
Type() 返回对象类型标识,用于在 OnChartEvent 中识别哪个控件触发了事件,以及做类型检查。
少量控件没问题。如果表格单元格很多,刷新时要注意只更新变化的部分,避免每个 tick 都重绘全部对象。