做面板这块,绕不开的就是对象事件处理,我当初在图表上画了一排按钮,点哪个都没反应,后来才发现是 CHARTEVENT_OBJECT_CLICK 的 sparam 没对上对象名,白折腾一晚上 😂 所以先给结论:MQL5 的交互面板本质是“画对象 + 接事件 + 回写状态”三件事,顺序错了就全是坑。
先说对象创建。我习惯用 OBJ_BUTTON 配 OBJ_RECTANGLE_LABEL 做底板,坐标全部用像素而不是价格轴,避免图表缩放后按钮乱飞。关键点是 OBJPROP_CORNER 和 OBJPROP_XDISTANCE/YDISTANCE 要成对设置,我踩过的坑是只改了 X 没改 Y,按钮直接跑到图表外,肉眼找不到还以为没创建成功。建议封装一个 CreateButton 函数,把名称、文本、坐标、颜色一次性传进去,后面批量改样式省事。
事件处理是重点。OnChartEvent 里要区分 CHARTEVENT_OBJECT_CLICK 和 CHARTEVENT_CHART_CHANGE,前者拿 sparam 比对按钮名,后者用来重绘。我的做法是:
还有个隐蔽的坑:面板按钮名如果和 EA 其他对象重名,点击会串。我现在的命名规则是 前缀_功能_序号,比如 pnl_btn_start_01,一眼能看出归属。另外 OnDeinit 里记得循环删除自己创建的对象,只删固定名字会漏,用 ObjectsDeleteAll(0, 前缀) 最稳。
最后提一句,面板逻辑别写死在 OnTick 里,交互和交易信号要解耦,不然回测时按钮事件根本触发不了,你测出来的结果和实盘对不上。你们做面板时是习惯用对象事件还是直接上 CAppDialog 那套标准库?我最近在纠结要不要把老面板迁过去,想听听实际用下来的感受。
先说对象创建。我习惯用 OBJ_BUTTON 配 OBJ_RECTANGLE_LABEL 做底板,坐标全部用像素而不是价格轴,避免图表缩放后按钮乱飞。关键点是 OBJPROP_CORNER 和 OBJPROP_XDISTANCE/YDISTANCE 要成对设置,我踩过的坑是只改了 X 没改 Y,按钮直接跑到图表外,肉眼找不到还以为没创建成功。建议封装一个 CreateButton 函数,把名称、文本、坐标、颜色一次性传进去,后面批量改样式省事。
事件处理是重点。OnChartEvent 里要区分 CHARTEVENT_OBJECT_CLICK 和 CHARTEVENT_CHART_CHANGE,前者拿 sparam 比对按钮名,后者用来重绘。我的做法是:
- 在 OnChartEvent 开头先判断 id == CHARTEVENT_OBJECT_CLICK
- 用 sparam 逐一比对按钮名,命中就执行对应逻辑
- 执行完立刻 ObjectSetInteger(0, name, OBJPROP_STATE, false) 复位按下状态,否则按钮会一直卡在按下态
- 状态变量单独存全局,别直接读对象属性,回测和实盘表现才一致
还有个隐蔽的坑:面板按钮名如果和 EA 其他对象重名,点击会串。我现在的命名规则是 前缀_功能_序号,比如 pnl_btn_start_01,一眼能看出归属。另外 OnDeinit 里记得循环删除自己创建的对象,只删固定名字会漏,用 ObjectsDeleteAll(0, 前缀) 最稳。
最后提一句,面板逻辑别写死在 OnTick 里,交互和交易信号要解耦,不然回测时按钮事件根本触发不了,你测出来的结果和实盘对不上。你们做面板时是习惯用对象事件还是直接上 CAppDialog 那套标准库?我最近在纠结要不要把老面板迁过去,想听听实际用下来的感受。
