MQL5 表格控件基础:三类二维数据展示类的骨架与属性(基础篇)
(1/3)·从文本标签到绘制型表格,理清控件组成与类结构再写界面少走弯路
在 MQL5 自定义面板里塞二维数据,很多人直接堆 Label 和 Edit 控件,滚动一多坐标就乱。表格控件的滚动条、锁定表头、可见区域计算若不在类里封装好,后期改一列宽度能牵动半个界面。本文先把三种表格类型的底层组成和类属性讲透,再谈扩展。
◍ 给 MT5 面板加一张可滚动的表格
在 MQL5 里做自定义图形界面,表格控件是最容易被低估的一块。它不像按钮或标签那样直来直去,但一旦跑起来,能把多品种报价、持仓明细或信号日志直接铺在图表上,省掉切窗口的麻烦。 官方示例工程发布于 2016 年 9 月 14 日,至今在客户端标准库里仍可找到对应实现,原贴浏览量约 3694 次、收藏 22 次——说明这套接口虽老,却仍是多数人抄作业的第一站。 表格本质是一个带行/列容器的 CTable 类封装,内部用 CEdit 或 CLable 做单元格。真正麻烦的是滚动条联动:当行数超过可视高度,必须自己处理 OnScroll 事件并重绘可视区,标准库给的 demo 已经把这套逻辑写死了,直接继承改字段即可。
控件选型前的目录地图
做 MT5 面板时,表格类控件至少有三条实现路径:文本标签堆砌、可编辑框承载、以及直接在 CCanvas 上自绘。原文给出的实战顺序是先吃透 CLabelsTable,再过渡到 CTable,最后用 CCanvasTable 解决高频重绘场景。 这 6 节原文里,表格相关开发占 4 节(两类封装 + 两类测试),说明多数坑不在画出来,而在交互与刷新。你开 MT5 新建 EA 面板前,先想清楚表格要不要用户改值——要改就别用纯标签方案,后续重构成本偏高。 目录里「结论」单独成节,意味着三种方案会有明确取舍基准,而不是堆代码。建议边读边在 MetaEditor 建三个空类骨架,对照着填,比纯看顺一遍留存率高得多。
「三类表格控件先铺开」
这一篇在界面库里落地了三个类,专门用来在 MQL 应用的图形界面里呈现二维数据。分别是文本标签型、编辑框型、绘制型表格,每种都有各自的适用场景和取舍。 文本标签型最轻量,只读展示优先;编辑框型允许终端用户直接改单元格内容,适合参数录入;绘制型则用图形对象画格子,灵活度最高但开销也最大。 原文把这三个类作为本章核心交付,档案里的文件需按原有目录结构原样放置,否则 MT5 加载时会找不到依赖。下一章会接着讲页面和带图形的页面控件,本篇先不展开。
◍ 文本标签型表格的内部构件
在 MT5 自定义指标或 EA 面板里,表格是最容易踩坑的 GUI 控件——它本身不是单一对象,而是把背景、文本标签和两套滚动条打包在一起的复合体。 当行数或列宽超过你给定的显示区域,垂直与水平滚动条就会接管视图偏移;若忽略这一点,数据写出来却看不到是常态。 该控件至少由四部分构成:底层背景、承载文字的文本标签、垂直滚动条、水平滚动条。理清这四块归属,后续写 CTable 派生类时才不会把坐标算错。
从零搭一个标签表格控件
在 MT5 自定义图形界面里,原生控件没有现成的「多行多列文字表」。要自己造一个 CLabelsTable,先建 LabelsTable.mqh,并在 WndContainer.mqh 里 include 它,把类挂进控件库。 表格在创建前要先定属性:行高、首列左缩进、列间距、背景色、文字色、首行/首列锁定模式、总行列数、可见行列数。文本标签锚点用 ANCHOR_CENTER,所以缩进和间距都按每列标签的中心点算,不是左缘对齐。 锁定模式值得单独说:首行(列名)和首列(序列名)可设成滚动时永远钉在顶部/左边。表头锁定能单独用也能组合用,实现时数据数组从索引 2 开始偏移即可保住表头。 TableSize() 和 VisibleTableSize() 两个方法传列、行两参数,内部会强制修正——列数小于 1 或行数小于 2 直接拦掉,避免数组越界。另用 LTLabels 结构存可见标签、LTOptions 存单元值与颜色。 构造函数里把所有属性设默认值,外部只暴露四个 private 加一个 public 方法,再补返回滚动条指针的接口方便用户配滚动。CreateLabels() 建标签数组时,对象名必须拼上列行索引,否则多单元会重名冲突。 改值用 SetValue(列,行,值)、读值用 GetValue(列,行),开头都做范围检查;想让正绿负红就调 TextColor(列,行,色)。改完必须调 UpdateTable() 才会重绘,它读滚动条滑块位置决定从哪偏移,双重循环搬数据和颜色。 左键按住滚动条快进的逻辑和之前 CListView 它们同构,不重复贴。复杂控件要把滚动条指针塞进指针库,WndContainer 里加对应数组,这部分前文已交待。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| WndContainer.mqh | class=class="str">"cmt">//| Copyright class="num">2015, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "LabelsTable.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 用于创建文字标签型表格的类 | class=class="str">"cmt">//+------------------------------------------------------------------+ class CLabelsTable : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 指向元件附加表单的指针 CWindow *m_wnd; class=class="str">"cmt">//--- class="kw">public: CLabelsTable(class="type">void); ~CLabelsTable(class="type">void); class=class="str">"cmt">//--- (class="num">1) 保存表单指针, (class="num">2) 返回滚动条的指针 class="type">void WindowPointer(CWindow &object) { m_wnd=::GetPointer(object); } class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 图表事件处理函数 class="kw">virtual class="type">void OnEvent(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">//--- 计时器 class="kw">virtual class="type">void OnEventTimer(class="type">void); class=class="str">"cmt">//--- 移动元件 class="kw">virtual class="type">void Moving(const class="type">int x,const class="type">int y); class=class="str">"cmt">//--- (class="num">1) 显示, (class="num">2) 隐藏, (class="num">3) 重置, (class="num">4) 删除
「标签表格类的空壳与绘制接口」
在 MT5 自定义控件体系里,CLabelsTable 作为 CElement 的派生类,先把显隐、重置、销毁这组生命周期接口全声明成虚函数,方便后续在子类里改写绘制逻辑。 Show、Hide、Reset、Delete 四个虚函数构成基础控制面,而 SetZorders 与 ResetZorders 专门管鼠标左键点击的层级优先级——这在多控件叠加的贵金属盯盘面板里,直接决定你点表头会不会误触到下方 K 线。 构造函数与析构函数目前都是空实现,说明这一版只是把架子搭好:CLabelsTable::CLabelsTable(void) {} 和 ~CLabelsTable(void) {} 里没有任何资源申请或释放动作。 私有成员已经把表格的几何与配色参数预留出来了:m_row_y_size 控制每行高度,m_x_offset 是第一列锚点到左边缘的距离,m_column_x_offset 管列间距,m_fix_first_row 与 m_fix_first_column 则决定是否冻结首行首列。外汇与贵金属图表挂这类浮动表,高杠杆下误读层级可能放大操作风险。 公开设值接口走的是内联写法,例如 AreaColor(const color clr){ m_area_color=clr; } 和 RowYSize(const int y_size){ m_row_y_size=y_size; },改一个参数即时写进成员变量,不用等重绘消息。你开 MT5 新建个空 EA 把这段类声明贴进去,编译能过就说明环境对齐了。
class="kw">virtual class="type">void Show(class="type">void); class="kw">virtual class="type">void Hide(class="type">void); class="kw">virtual class="type">void Reset(class="type">void); class="kw">virtual class="type">void Delete(class="type">void); class=class="str">"cmt">//--- (class="num">1) 设置, (class="num">2) 重设鼠标左键点击的优先级 class="kw">virtual class="type">void SetZorders(class="type">void); class="kw">virtual class="type">void ResetZorders(class="type">void); class=class="str">"cmt">//--- 重置颜色 class="kw">virtual class="type">void ResetColors(class="type">void) {} }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 构造函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ CLabelsTable::CLabelsTable(class="type">void) { } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 析构函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ CLabelsTable::~CLabelsTable(class="type">void) { } class CLabelsTable : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 每行高度 class="type">int m_row_y_size; class=class="str">"cmt">//--- 表格背景颜色 class="type">color m_area_color; class=class="str">"cmt">//--- 表格文字的默认颜色 class="type">color m_text_color; class=class="str">"cmt">//--- 第一列的中心锚点与控件左方边缘的距离 class="type">int m_x_offset; class=class="str">"cmt">//--- 列间锚点的距离 class="type">int m_column_x_offset; class=class="str">"cmt">//--- 第一行的锁定模式 class="type">bool m_fix_first_row; class=class="str">"cmt">//--- 第一列的锁定模式 class="type">bool m_fix_first_column; class=class="str">"cmt">//--- 鼠标左键点击优先级 class="type">int m_zorder; class="type">int m_area_zorder; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- (class="num">1) 背景颜色, (class="num">2) 文字颜色 class="type">void AreaColor(const class="type">color clr) { m_area_color=clr; } class="type">void TextColor(const class="type">color clr) { m_text_color=clr; } class=class="str">"cmt">//--- (class="num">1) 行的高度, (class="num">2) 设置第一列锚点与表格左方边缘的距离, class=class="str">"cmt">// (class="num">3) 设置列间锚点的距离 class="type">void RowYSize(const class="type">int y_size) { m_row_y_size=y_size; }