如何创建任意复杂度的图形面板·进阶篇
(2/3)· 从对象继承到 #undef 重定义,把面板底层逻辑一次讲透
◍ 拆解 CAppDialog 的图层堆叠顺序
在空白图表挂上 LearnCAppDialog.mq5 后,按 Ctrl+B 再点“全部”,对象列表里能直接看到面板拉起的全部图形元素。标准库面板与对话框这套对象,创建次序是固定的:先生成 Border 边框,再往里铺 Back 背景层,背景之上才是 ClientBack 客户区,子控件全加在客户区里,标题和那两个控制按钮压在顶部。 Border 本体是 OBJ_RECTANGLE_LABEL,默认套了白色边框。它纯粹是装饰——白色边线露在外头,主体很快被 Back 层盖住,所以别指望 Border 承载任何交互逻辑,它只负责让面板边缘有那圈白线。 实测里这套顺序乱不得:若先建 Back 再补 Border,边框会被背景吞掉,Ctrl+B 里对象还在,但视觉上白边消失。开 MT5 拖一遍就能确认图层覆盖关系。
「面板类的继承与创建分支」
标准库里面板相关的类看似多,继承链其实很浅。只要搞清 CAppDialog 装了什么、怎么建,其余类基本一通百通。 以 LearnCAppDialog.mq5 里的 AppWindow 面板为例,它挂了 6 个对象,各自只干一件具体活。基于 CAppDialog 的面板既能生在 EA 里,也能生在指标里,但创建路径被程序类型和窗口号卡死了。 若运行程序是 PROGRAM_EXPERT,面板只允许落在主窗口(索引 0),且只能走 CAppDialog::CreateExpert。若是 PROGRAM_INDICATOR,则先看窗口号:0 号主窗口用 CreateIndicator,子窗口反而要用 CreateExpert。 CreateIndicator 有个硬差异——建面板时会自动把宽度对齐窗口、并按需拉高窗口容纳面板。指标示例 [data folder]\MQL5\Indicators\Examples\Panels\SimplePanel\SimplePanel.mq5 建完还能最小化,就是这套逻辑。唯一的例外是指标也可强占主窗口建面板,此时仍调 CreateIndicator。外汇与贵金属脚本挂载面板属高风险操作,建窗失败可能拖慢盯盘响应。
用 #undef 改写面板控件的默认常数
MT5 标准库里面板和控件的基础常数都躺在 [数据文件夹]\MQL5\Include\Controls\Defines.mqh 中,被 CWnd 体系引用。继承链是 CWnd → CWndContainer → CDialog → CAppDialog,我们真正要动的就是那批宏替换。 想改这些宏,得先用 #undef 把已声明的宏撤掉,再用新参数重声明。诀窍是在包含 Dialog.mqh 之前先 include Defines.mqh,紧接着 #undef 掉目标宏,然后把输入参数写进去当新值重声明。这样 EA 编译时用的就是你的配色而不是库默认。 CAppDialog 对象自带从 CWndContainer 继承来的 ControlsTotal 方法,能数出容器里控件数量并逐个遍历。调试器里能看到对象创建后的命名规律:m_background 变成 "29437Back"、m_client_area 变成 "29437Client",前面那串 29437 是面板生命周期内的唯一标识。 别把正态当圣经 改 m_client_area 或 m_background 颜色很直接,但注意若调用 CWndContainer::Delete 把 m_client_area 从组里摘除,之后拖面板时客户区不会跟手,会卡在原位;关闭面板时它才随其他元件一起被删。若改用 CWndContainer::Destroy,则是直接销毁对象——示例代码里面板建好后有 5 秒暂停再干掉客户区。外汇与贵金属脚本改动 UI 不影响报价风险,但 MT5 图形对象误操作可能导致图表状态混乱,实盘前请在模拟盘验证。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Wnd.mqh | class=class="str">"cmt">//| Copyright class="num">2009-class="num">2017, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "Rect.mqh" class="macro">#include "Defines.mqh" class="macro">#include <Object.mqh> class CDragWnd; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 绘图风格和颜色 | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- 通用 class="macro">#define CONTROLS_FONT_NAME "Trebuchet MS" class="macro">#define CONTROLS_FONT_SIZE(class="num">10) class=class="str">"cmt">//--- 文字 class="macro">#define CONTROLS_COLOR_TEXT C&class="macro">#x27;0x3B,0x29,0x28&class="macro">#x27; class="macro">#define CONTROLS_COLOR_TEXT_SEL White class="macro">#define CONTROLS_COLOR_BG White class="macro">#define CONTROLS_COLOR_BG_SEL C&class="macro">#x27;0x33,0x99,0xFF&class="macro">#x27; class=class="str">"cmt">//--- 按钮 class="macro">#define CONTROLS_BUTTON_COLOR C&class="macro">#x27;0x3B,0x29,0x28&class="macro">#x27; class="macro">#define CONTROLS_BUTTON_COLOR_BG C&class="macro">#x27;0xDD,0xE2,0xEB&class="macro">#x27; class="macro">#define CONTROLS_BUTTON_COLOR_BORDER C&class="macro">#x27;0xB2,0xC3,0xCF&class="macro">#x27; class=class="str">"cmt">//--- 标签 class="macro">#define CONTROLS_LABEL_COLOR C&class="macro">#x27;0x3B,0x29,0x28&class="macro">#x27; class=class="str">"cmt">//--- 编辑框 class="macro">#define CONTROLS_EDIT_COLOR C&class="macro">#x27;0x3B,0x29,0x28&class="macro">#x27;
◍ 控件配色宏定义逐个拆
在 MT5 自定义面板开发里,所有标准控件的底色、边框色都靠一组 #define 宏集中管理。改一处宏,整个 EA 面板的美观度就跟着变,不用去翻每个 CEdit、CList 的创建代码。 下面是编辑框、滚动条、列表视图等核心控件的配色宏原文: #define CONTROLS_EDIT_COLOR_BG White #define CONTROLS_EDIT_COLOR_BORDER C'0xB2,0xC3,0xCF' //--- 滚动条 #define CONTROLS_SCROLL_COLOR_BG C'0xEC,0xEC,0xEC' #define CONTROLS_SCROLL_COLOR_BORDER C'0xD3,0xD3,0xD3' //--- 客户区域 #define CONTROLS_CLIENT_COLOR_BG C'0xDE,0xDE,0xDE' #define CONTROLS_CLIENT_COLOR_BORDER C'0x2C,0x2C,0x2C' //--- 列表视图 #define CONTROLS_LISTITEM_COLOR_TEXT C'0x3B,0x29,0x28' #define CONTROLS_LISTITEM_COLOR_TEXT_SEL White #define CONTROLS_LISTITEM_COLOR_BG White #define CONTROLS_LISTITEM_COLOR_BG_SEL C'0x33,0x99,0xFF' #define CONTROLS_LIST_COLOR_BG White #define CONTROLS_LIST_COLOR_BORDER C'0xB2,0xC3,0xCF' //--- 复选框组 #define CONTROLS_CHECKGROUP_COLOR_BG C'0xF7,0xF7,0xF7' #define CONTROLS_CHECKGROUP_COLOR_BORDER C'0xB2,0xC3,0xCF' //--- 单选框组 #define CONTROLS_RADIOGROUP_COLOR_BG C'0xF7,0xF7,0xF7' #define CONTROLS_RADIOGROUP_COLOR_BORDER C'0xB2,0xC3,0xCF' //--- 对话框 #define CONTROLS_DIALOG_COLOR_BORDER_LIGHT White #define CONTROLS_DIALOG_COLOR_BORDER_DARK C'0xB6,0xB6,0xB6' #define CONTROLS_DIALOG_COLOR_BG C'0xF0,0xF0,0xF0' #define CONTROLS_DIALOG_COLOR_CAPTION_TEXT C'0x28,0x29,0x3B' #define CONTROLS_DIALOG_COLOR_CLIENT_BG C'0xF7,0xF7,0xF7' #define CONTROLS_DIALOG_COLOR_CLIENT_BORDER C'0xC8,0xC8,0xC8' 逐行看:CONTROLS_EDIT_COLOR_BG 设为 White,编辑框底色纯白;CONTROLS_EDIT_COLOR_BORDER 用 C'0xB2,0xC3,0xCF' 即浅蓝灰边框。滚动条底色 C'0xEC,0xEC,0xEC' 接近浅灰,边框 C'0xD3,0xD3,0xD3' 略深。 列表视图里选中项底色是 C'0x33,0x99,0xFF'(典型 Windows 蓝),未选中文本用 C'0x3B,0x29,0x28' 深棕,对比度足够。对话框标题文字 C'0x28,0x29,0x3B' 近黑蓝,客户区底色 C'0xF7,0xF7,0xF7' 比主背景 C'0xF0,0xF0,0xF0' 稍亮。 把这组宏直接贴进你的 .mq5,把 CONTROLS_LISTITEM_COLOR_BG_SEL 改成 C'0xFF,0x99,0x00' 之类,就能在 MT5 里直观看到自选品种列表高亮色变了。外汇与贵金属交易界面定制虽不影响报价,但过度依赖面板信号仍属高风险行为。
class="macro">#define CONTROLS_EDIT_COLOR_BG White class="macro">#define CONTROLS_EDIT_COLOR_BORDER C&class="macro">#x27;0xB2,0xC3,0xCF&class="macro">#x27; class=class="str">"cmt">//--- 滚动条 class="macro">#define CONTROLS_SCROLL_COLOR_BG C&class="macro">#x27;0xEC,0xEC,0xEC&class="macro">#x27; class="macro">#define CONTROLS_SCROLL_COLOR_BORDER C&class="macro">#x27;0xD3,0xD3,0xD3&class="macro">#x27; class=class="str">"cmt">//--- 客户区域 class="macro">#define CONTROLS_CLIENT_COLOR_BG C&class="macro">#x27;0xDE,0xDE,0xDE&class="macro">#x27; class="macro">#define CONTROLS_CLIENT_COLOR_BORDER C&class="macro">#x27;0x2C,0x2C,0x2C&class="macro">#x27; class=class="str">"cmt">//--- 列表视图 class="macro">#define CONTROLS_LISTITEM_COLOR_TEXT C&class="macro">#x27;0x3B,0x29,0x28&class="macro">#x27; class="macro">#define CONTROLS_LISTITEM_COLOR_TEXT_SEL White class="macro">#define CONTROLS_LISTITEM_COLOR_BG White class="macro">#define CONTROLS_LISTITEM_COLOR_BG_SEL C&class="macro">#x27;0x33,0x99,0xFF&class="macro">#x27; class="macro">#define CONTROLS_LIST_COLOR_BG White class="macro">#define CONTROLS_LIST_COLOR_BORDER C&class="macro">#x27;0xB2,0xC3,0xCF&class="macro">#x27; class=class="str">"cmt">//--- 复选框组 class="macro">#define CONTROLS_CHECKGROUP_COLOR_BG C&class="macro">#x27;0xF7,0xF7,0xF7&class="macro">#x27; class="macro">#define CONTROLS_CHECKGROUP_COLOR_BORDER C&class="macro">#x27;0xB2,0xC3,0xCF&class="macro">#x27; class=class="str">"cmt">//--- 单选框组 class="macro">#define CONTROLS_RADIOGROUP_COLOR_BG C&class="macro">#x27;0xF7,0xF7,0xF7&class="macro">#x27; class="macro">#define CONTROLS_RADIOGROUP_COLOR_BORDER C&class="macro">#x27;0xB2,0xC3,0xCF&class="macro">#x27; class=class="str">"cmt">//--- 对话框 class="macro">#define CONTROLS_DIALOG_COLOR_BORDER_LIGHT White class="macro">#define CONTROLS_DIALOG_COLOR_BORDER_DARK C&class="macro">#x27;0xB6,0xB6,0xB6&class="macro">#x27; class="macro">#define CONTROLS_DIALOG_COLOR_BG C&class="macro">#x27;0xF0,0xF0,0xF0&class="macro">#x27; class="macro">#define CONTROLS_DIALOG_COLOR_CAPTION_TEXT C&class="macro">#x27;0x28,0x29,0x3B&class="macro">#x27; class="macro">#define CONTROLS_DIALOG_COLOR_CLIENT_BG C&class="macro">#x27;0xF7,0xF7,0xF7&class="macro">#x27; class="macro">#define CONTROLS_DIALOG_COLOR_CLIENT_BORDER C&class="macro">#x27;0xC8,0xC8,0xC8&class="macro">#x27;
「给控制面板换一套自定义配色」
想在 MT5 里做带位图按钮的交易面板,第一步往往是改掉标准控件库的默认灰白配色。标准 Controls 库在 Defines.mqh 里用宏写死了字体、按钮和对话框颜色,直接 include 会覆盖不了你的 input 参数。 正确做法是在 include 之前先用 #undef 把 12 个相关宏全部撤掉,再用 #define 把它们重映射到脚本顶部声明的 input 变量上。下面这段就是典型的预处理重定义块,覆盖了字体名、字号、按钮前景/背景/边框、对话框边框明暗与背景等。 注意字体默认设成了 Trebuchet MS、字号 10,按钮文字色用了 C'0x3B,0x29,0x28'(深棕),背景是 C'0xDD,0xE2,0xEB'(浅蓝灰)。这些数值你都能在 MT5 里直接改,然后看面板实时变色。外汇与贵金属行情波动剧烈,这类面板只做交互辅助,不涉及任何方向判断。 预处理做完再 include Dialog.mqh 和 BmpButton.mqh,CBmpButton 类就能用你这套配色实例化。开 MT5 新建 EA 把下面代码贴进头部,编译后拖到图表即可验证面板颜色是否生效。
class="macro">#class="kw">property description "控制面板与对话框. 演示 CBmpButton 类" class="macro">#include <Controls\Defines.mqh> class="macro">#undef CONTROLS_FONT_NAME class="macro">#undef CONTROLS_FONT_SIZE class="macro">#undef CONTROLS_BUTTON_COLOR class="macro">#undef CONTROLS_BUTTON_COLOR_BG class="macro">#undef CONTROLS_BUTTON_COLOR_BORDER class="macro">#undef CONTROLS_DIALOG_COLOR_BORDER_LIGHT class="macro">#undef CONTROLS_DIALOG_COLOR_BORDER_DARK class="macro">#undef CONTROLS_DIALOG_COLOR_BG class="macro">#undef CONTROLS_DIALOG_COLOR_CAPTION_TEXT class="macro">#undef CONTROLS_DIALOG_COLOR_CLIENT_BG class="macro">#undef CONTROLS_DIALOG_COLOR_CLIENT_BORDER input class="type">class="kw">string font_name = "Trebuchet MS"; input class="type">int font_size = class="num">10; input class="type">color button_color = C&class="macro">#x27;0x3B,0x29,0x28&class="macro">#x27;; input class="type">color button_color_bg = C&class="macro">#x27;0xDD,0xE2,0xEB&class="macro">#x27;; input class="type">color button_color_border = C&class="macro">#x27;0xB2,0xC3,0xCF&class="macro">#x27;; input class="type">color dialog_color_border_light = White; input class="type">color dialog_color_border_dark = C&class="macro">#x27;0xB6,0xB6,0xB6&class="macro">#x27;; input class="type">color dialog_color_bg = C&class="macro">#x27;0xF0,0xF0,0xF0&class="macro">#x27;; input class="type">color dialog_color_caption_text = C&class="macro">#x27;0x28,0x29,0x3B&class="macro">#x27;; input class="type">color dialog_color_client_bg = C&class="macro">#x27;0xF7,0xF7,0xF7&class="macro">#x27;; input class="type">color dialog_color_client_border = C&class="macro">#x27;0xC8,0xC8,0xC8&class="macro">#x27;; class="macro">#define CONTROLS_FONT_NAME font_name class="macro">#define CONTROLS_FONT_SIZE font_size class="macro">#define CONTROLS_BUTTON_COLOR button_color class="macro">#define CONTROLS_BUTTON_COLOR_BG button_color_bg class="macro">#define CONTROLS_BUTTON_COLOR_BORDER button_color_border class="macro">#define CONTROLS_DIALOG_COLOR_BORDER_LIGHT dialog_color_border_light class="macro">#define CONTROLS_DIALOG_COLOR_BORDER_DARK dialog_color_border_dark class="macro">#define CONTROLS_DIALOG_COLOR_BG dialog_color_bg class="macro">#define CONTROLS_DIALOG_COLOR_CAPTION_TEXT dialog_color_caption_text class="macro">#define CONTROLS_DIALOG_COLOR_CLIENT_BG dialog_color_client_bg class="macro">#define CONTROLS_DIALOG_COLOR_CLIENT_BORDER dialog_color_client_border class="macro">#include <Controls\Dialog.mqh> class="macro">#include <Controls\BmpButton.mqh>
对话框基类的控件装配逻辑
CDialog 是 MT5 标准库中对话框与指标面板的共同基类,它不直接画界面,而是把五个底层控件拼起来:白色边框、背景、标题栏、关闭按钮、客户区。这五个成员在 private 段声明,外部只能透过类方法去驱动。 Create() 是整个装配入口。它先调父类 CWndContainer::Create() 确立图表、名称、子窗口与坐标边界(x1,y1,x2,y2),任一依赖控件构建失败就返回 false,对话框直接起不来。 注意 m_panel_flag 这个开关:只有当它为真时才跳过白色边框的创建,意味着默认每个对话框都带边框。如果你在做极简面板,记得在实例化前把该标志置位,否则多一层 CPanel 会吃掉约 2~3 像素的边距。 下面这段是类定义与 Create 方法的核心骨架,逐行拆完就能在 MT5 里照抄验证。
class CDialog : class="kw">public CWndContainer { class="kw">private: CPanel m_white_border; class=class="str">"cmt">// "白色边框" 对象 CPanel m_background; class=class="str">"cmt">// 背景对象 CEdit m_caption; class=class="str">"cmt">// 窗口标题对象 CBmpButton m_button_close; class=class="str">"cmt">// "关闭"按钮对象 CWndClient m_client_area; class=class="str">"cmt">// 客户区域对象 class="kw">protected: class="type">bool CDialog::Create(const class="type">long chart,const class="type">class="kw">string name,const class="type">int subwin,const class="type">int x1,const class="type">int y1,const class="type">int x2,const class="type">int y2) { if(!CWndContainer::Create(chart,name,subwin,x1,y1,x2,y2)) class="kw">return(class="kw">false); if(!m_panel_flag && !CreateWhiteBorder()) class="kw">return(class="kw">false); if(!CreateBackground()) class="kw">return(class="kw">false); if(!CreateCaption()) class="kw">return(class="kw">false); if(!CreateButtonClose()) class="kw">return(class="kw">false); if(!CreateClientArea()) class="kw">return(class="kw">false);