首页 / 交易学院 / 小布知识库 / 自定义图形控件(二):把控件做成 IncGUI 库
自定义图形控件(二):把控件做成 IncGUI 库
📚

自定义图形控件(二):把控件做成 IncGUI 库

MQL5 编程 难度 · 进阶 2013 12 分钟阅读
GUI库控件IncGUI面向对象MQL5

一、上篇回顾与本文目标

上篇讲了标准控件体系与事件路由。本篇更进一步:从 CControl 继承,自建一个能画、能点、能暴露属性的自定义控件。目标不是炫技,而是把'标准控件做不到的显示'变成可复用组件。

二、从 CControl 继承:必须重写的方法

自建控件要继承 CControl,至少重写构造(设尺寸)、绘制入口、事件处理。CControl 已经把坐标、可见性、父控件管好了,你只补'这个控件长什么样、怎么响应'。

最小必重写:① 设置尺寸的构造 ② 绘制方法(交给 Canvas)③ 鼠标/键盘事件处理。其余通用行为复用基类即可。

三、绘制:OnDraw 与 Canvas 配合

绘制逻辑写在控件的绘制方法里,用 Canvas 画线、矩形、文字。注意只画自己这一块区域,别越界覆盖兄弟控件;图表缩放或数据变化时,由父窗口触发重绘。

四、事件:鼠标与键盘怎么接

控件在父窗口的事件分发中按自己的 ID 收到鼠标/键盘消息。你在处理函数里判断点击位置是否落在控件矩形内,再决定高亮、按下、选中等状态。命中检测用'点是否在矩形内'即可。

五、属性与方法:对外暴露什么

好的自定义控件只暴露必要的属性(如数值、颜色、是否启用)和方法(如 SetValue/GetValue/Redraw)。内部状态私有,外部通过方法改,避免被随意改坏。这点和上篇类图思想一致。

六、一个最小可运行示例

以'带数值显示的圆形按钮'为例:继承 CControl,构造里定半径;绘制时画圆+居中数值;点击命中检测判断点到圆心距离≤半径;SetValue 改数值后触发 Redraw。几十行就能跑起来,是上手自定义控件的最佳练手。

七、调试与常见坑

最常踩的坑:重绘没触发(忘了调父窗口 Redraw 或没在 OnChartEvent 转发)、坐标没换算图表缩放、命中区域和绘制区域不一致。逐一打印状态就能定位。

调试顺序:① 事件有没有进控件 ② 命中检测对不对 ③ 绘制有没有被调用 ④ 缩放下坐标对不对。多数问题出在 ① 或 ④。

八、最小示例的伪代码走读

圆形按钮的绘制方法里:先按背景色画圆,再在圆心用 Canvas 写当前数值;事件处理里计算“点到圆心距离是否 ≤ 半径”判定命中,命中则切到按下状态并 Redraw。SetValue 改数值后同样触发 Redraw。整条链路就是“构造定尺寸 → 绘制画自己 → 事件做命中 → 改值就重绘”,几十行即可跑通。

九、复用与扩展

性能提醒:自定义控件每次状态变更都会触发重绘。高频更新(如每个 tick 改数值)务必先判断“值是否真的变了”,没变就跳过 Redraw,否则图表会明显卡顿。这是自建控件最容易踩、也最易被忽略的性能坑——重绘要“按需”,不要“每改必画”。
工程提示:自定义控件先在一个最小 demo 里跑通再嵌进 EA,能大幅隔离“这是控件本身的 bug,还是 EA 调用逻辑的 bug”的排查成本,上线前必做这一步。

十、小结

自建控件 = 继承 CControl + 重写绘制与事件 + 只暴露必要属性方法。绘制交给 Canvas 并守好自己的区域,事件靠'点是否在矩形/圆内'做命中检测,状态变更后触发重绘。把它当成上篇类图思想的落地:内部状态私有、对外只给干净接口,自定义显示就能稳定复用。

常见问题

不难。继承 CControl,重写构造、绘制(用 Canvas)、事件处理三处即可;最小可运行示例几十行。难点在重绘触发与坐标缩放,而非框架本身。
至少三个:设置尺寸的构造、绘制方法(内部用 Canvas 画)、鼠标/键盘事件处理。其它通用行为(坐标、可见性、父控件)直接复用 CControl 基类。
绘制与命中检测都要用图表当前缩放换算坐标,不能写死像素;缩放变化由父窗口触发重绘。坐标不一致是最高频的坑。
能。自定义控件内部完全可以组合或调用标准控件(如 CButton),也可把标准控件当作子控件 Add 进自己的容器,逐步替换做不到的部分。