基于 CChartObject 类设计和实施新 GUI 组件·综合运用
(3/3)· 从基类派生到动态二维数组表格,把 MQL5 标准库的 GUI 扩展能力一次性用透
用二维数组搭可变色 MTF 指标表格
在多时间表 EA 里,常需要把不同周期的指标值分格显示。原生 MT5 没有现成的二维表格控件,逐个画矩形不仅繁琐,改色和填字也得重复写逻辑。 CChartObjectEditTable 这个类用指向 CArrayObj 的指针 array2D 存了一个“数组的数组”:外层每一列是一个 CArrayObj,里面再塞 CChartObjectEdit 单元格对象。m_rows、m_cols 记行列数,m_baseName 给所有单元格名加统一前缀,便于后续定位。 代码里 Create() 的默认参数是 rows=1、cols=1、sizeX=15、sizeY=15、deltaX=5、deltaY=5,也就是说不传参时只会生成一个 15×15 像素、间距 5 的小编辑框。实际做 MTF 面板时,按周期数设 cols、按指标线数设 rows 即可。 SetColor() 和 SetText() 都先按列找 array2D 里的子数组,再用行号取第 n 个 CChartObjectEdit,分别调 BackColor() 和 Description()。想让某周期某指标格变红,直接 SetColor(行, 列, Red) 就行,不用重画对象。 外汇与贵金属杠杆高、滑点跳空频繁,这类表格只做信息呈现,不构成任何方向暗示;开着 MT5 把下面类头文件和 Create 逻辑抄进脚本,挂不同品种验证行列偏移是否符合预期。
class CChartObjectEditTable { class="kw">private: CArrayObj *array2D; class="type">int m_rows; class="type">int m_cols; class="type">class="kw">string m_baseName; class="kw">public: class="type">bool Create(class="type">long chart_id,class="type">class="kw">string name,class="type">int window,class="type">int rows,class="type">int cols,class="type">int startX,class="type">int startY,class="type">int class="type">int sizeX,class="type">int sizeY,class="type">class="kw">color Bg,class="type">int deltaX,class="type">int deltaY); class="type">bool Delete(); class="type">bool SetColor(class="type">int row,class="type">int col,class="type">class="kw">color newColor); class="type">class="kw">color GetColor(class="type">int row,class="type">int col); class="type">bool SetText(class="type">int row,class="type">int col,class="type">class="kw">string newText); class="type">class="kw">string GetText(class="type">int row,class="type">int col); }; class="type">bool CChartObjectEditTable::Create(class="type">long chart_id,class="type">class="kw">string name,class="type">int window,class="type">int rows=class="num">1,class="type">int cols=class="num">1,class="type">int class="type">int startX=class="num">0,class="type">int startY=class="num">0,class="type">int sizeX=class="num">15,class="type">int sizeY=class="num">15, class="type">class="kw">color Bg=White,class="type">int deltaX=class="num">5,class="type">int deltaY=class="num">5) { m_rows=rows; m_cols=cols; m_baseName=name; class="type">int i=class="num">0,j=class="num">0; array2D=new CArrayObj(); if (array2D==NULL) class="kw">return class="kw">false; for(j=class="num">0; j<m_cols; j++) { CArrayObj *new_array=new CArrayObj(); if (array2D==NULL) class="kw">return class="kw">false; array2D.Add(new_array); for(i=class="num">0; i<m_rows; i++) { CChartObjectEdit *new_edit=new CChartObjectEdit(); new_edit.Create(chart_id, name+IntegerToString(i)+":"+IntegerToString(j), window, startX+j*(sizeX+deltaX), startY+i*(sizeY+deltaY), sizeX, sizeY); new_edit.BackColor(Bg); new_edit.Color(White); new_edit.Selectable(class="kw">false);
◍ 表格控件的读写与销毁接口
上面这段把可编辑表格类收了尾:先给新建的编辑框设为只读并清空描述,再塞进列数组里,整个创建流程返回 true 表示成功。 SetColor 和 GetColor 都走同一个寻址逻辑——先用列号从 array2D 取子数组,再用行号取具体的 CChartObjectEdit 指针。越界一律返回 false 或 NULL,所以调用前得自己保证 row 在 [0, m_rows)、col 在 [0, m_cols)。 SetText 只改 Description,不改只读属性;想动态改内容又怕用户手滑,就保持 ReadOnly(true) 然后频繁调它。 Delete 里先按列清掉每个子数组再 delete,最后释放 array2D 本身,漏掉任意一层都会留内存尾巴。 实际挂表时这样落:table.Create(0,"t",0,1,10,10,10,15,15,Yellow) 建 10×10 格、左上角偏移 (1,10);table.SetColor(2,2,Red) 把第 3 行第 3 列染红,table.SetText(2,2,"2") 写个标记。外汇贵金属图表上叠这种表属于高风险辅助显示,参数错乱可能挡住价格本身。
new_edit.ReadOnly(true); new_edit.Description(""); new_array.Add(new_edit); } } class="kw">return true; } class="type">bool CChartObjectEditTable::SetColor(class="type">int row,class="type">int col,class="type">class="kw">color newColor) { CArrayObj *sub_array; CChartObjectEdit *element; if((row>=class="num">0 && row<m_rows) && (col>=class="num">0 && col<m_cols)) { if(array2D!=NULL) { sub_array=array2D.At(col); element=(CChartObjectEdit*)sub_array.At(row); element.BackColor(newColor); class="kw">return true; } } class="kw">return class="kw">false; } class="type">class="kw">color CChartObjectEditTable::GetColor(class="type">int row,class="type">int col) { CArrayObj *sub_array; CChartObjectEdit *element; if((row>=class="num">0 && row<m_rows) && (col>=class="num">0 && col<m_cols)) { if(array2D!=NULL) { sub_array=array2D.At(col); element=(CChartObjectEdit*)sub_array.At(row); class="kw">return element.BackColor(); } } class="kw">return NULL; } class="type">bool CChartObjectEditTable::SetText(class="type">int row,class="type">int col,class="type">class="kw">string newText) { CArrayObj *sub_array; CChartObjectEdit *element; if((row>=class="num">0 && row<m_rows) && (col>=class="num">0 && col<m_cols)) { if(array2D!=NULL) { sub_array=array2D.At(col); element=(CChartObjectEdit*)sub_array.At(row); element.Description(newText); class="kw">return true; } } class="kw">return class="kw">false; } class="type">bool CChartObjectEditTable::Delete(class="type">void) { for(class="type">int j=class="num">0; j<m_cols; j++) { CArrayObj *column_array=array2D.At(j); column_array.Clear(); class="kw">delete column_array; } class="kw">delete array2D; class="kw">return true; } table.Create(class="num">0,"t",class="num">0,class="num">1,class="num">10,class="num">10,class="num">10,class="num">15,class="num">15,Yellow); table.SetColor(class="num">2,class="num">2,Red); table.SetText(class="num">2,class="num">2,"class="num">2");
「记住这一条就够了」
把扩展控件接进 EA 或指标,核心动作只有一件:在代码里 include 那个 ChartObjectsExtControls.mqh 头文件,控件就能像原生对象一样被调用。 随文给的 zip 里,chartobjectextcontrols.mqh 占 28.87 KB,edittabledemo.mq5、progressbarea.mq5、spinnerdemoea.mq5 三个演示分别约 8.26 KB、7.17 KB、5.49 KB,直接丢进 MT5 的 MQL5 目录就能编译跑通。 派生自 CChartObject 的组件本身不复杂,真正要留意的从来不是写法,而是你打算把它绑到哪类行情逻辑上——外汇和贵金属波动跳点频繁,用这类控件做面板交互时得先想清楚重绘触发频率,否则容易在重大数据窗口卡 UI。