图形界面 IX 颜色选择器控件:从零搭出可交互调色盘基础篇(基础篇)
(1/3)· 想在 MQL5 程序里让用户随手改控件颜色,却卡在调色盘结构看不懂?这篇先把组成与类骨架讲透
本文是图形界面开发系列第九部的第 1/3 篇,聚焦颜色选择器控件的概念铺垫与 CColorPicker 类基础结构。在动手写界面之前,先理清调色盘由哪些部件和颜色模型组成,后续两篇才能直接上开发与测试。
◍ 给 MT5 面板加个取色控件
在 MT5 自建图形界面时,原生标准库并没有直接可用的颜色选择器。Anatoli Kazharski 在 2016-10-18 发布的示例中,用 CColorPicker 类补齐了这一空缺,原帖浏览量 4017、收藏 12,说明这类底层控件需求并不小众。 该控件核心思路是封装一个可点击的颜色按钮,弹出调色面板后把选中值回写给调用方。对于做价格行为分析面板的交易者,这意味着可以把均线、K线背景、流动性区间的高亮色做成运行时可调,而不是写死在代码里。 外汇与贵金属市场波动剧烈、杠杆风险高,这类界面改造只解决交互效率,不改变任何信号胜率,验证时请在策略测试器以外的演示账户先跑通。
从零理清这套界面库怎么放
这套 MQL5 界面开发库不是单篇能啃完的,它的结构从第一篇《图形界面 I: 库结构的准备工作 (第一章)》就开始铺。想搞懂当前开发库要干什么,先把那篇读掉,否则后面控件类全是空中阁楼。 每个部分文章末尾都挂着章节链接列表,同时能下载到当前阶段的完整库文件。重点:压缩包里的目录层级不能动,解压后必须按原位置原样丢进相同目录,MT5 才能正常索引到头文件和资源。 到系列第九部,会落地这几类控件:第一章是颜色选择器 CColorPicker 与颜色按钮 CColorButton;第二章是进度条 CProgressBar 与线性图表 CLineGraph。每篇都附可直接抄进 EA 的实例,展示这些元件怎么在实盘程序里被驱动。
「MT5里的颜色选择器到底由什么拼成」
在 MT5 的自绘面板或 EA 可视化设置界面里,调色盘不是单一对象,而是一组组合控件的集合。它能让使用者在 MQL 应用运行时直接改控件颜色,省去改代码重编译的麻烦。 拆开看,一个完整的颜色选择器至少包含:背景层、按指定颜色模型绘制的调色区、已选色标记、悬停色标记、带编辑框的单选按钮组(人工输色用)、取消按钮、以及把当前色固定到标记里的确认按钮。 它支持三种颜色模型切换:HSL(H 0–360,S/L 0–100)、RGB(R/G/B 各 0–255)、Lab(L 0–100,a 与 b 均为 -128 到 127,分别控制绿—粉红、蓝—黄通道)。在面板里这三个模型各是一组三个单选按钮,点哪个就切到哪种坐标空间。 后面我们要直接看 CColorPicker 类的实现,你可以在 MT5 里新建一个 empty panel 把这类挂上去,拖动单选按钮就能实时看到背景色随 HSL 的 H 值 0–360 循环变化。外汇与贵金属界面开发属高风险环境,参数误设可能导致显示异常,请在策略测试器先验证。
◍ 颜色选择器控件的类结构搭建
在 MT5 的 MQLX\Include\EasyAndFastGUI\Controls 目录下新建 ColorPicker.mqh,把 CColorPicker 类放进去。它继承自 CElement,需要把 Element.mqh 和 Window.mqh 一并 include,否则编译期就拿不到基类和窗体指针。 这个类总共用了 17 个 private 方法加 1 个 public 方法来拼出调色板界面。private 里先存一个 CWindow* m_wnd,用来回指控件挂着的表单,public 里用 WindowPointer() 把外部窗体指针写进去。 调色板不是写死尺寸的。绘制时按每个像素点算颜色,计算基准是调色板当前宽高,所以同样一套代码可以出正方形也可以出别的形状。附件里给过一张 500x255 像素的实例图,你可以照着自己改尺寸验证。 RGB 转 Lab 在基类 CColors 里没有直转方法,得走 RGB -> XYZ -> Lab 两段式。类中要声明对应栏位把各颜色模型的组分值存下来,切换单选按钮时再把选中索引传进对应绘制方法。 下面这段是类声明骨架,看得出公开接口只暴露了构造、事件、计时器和移动,其余绘制与计算全藏在 private,实际写的时候别漏了 WindowPointer 这行赋值。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| ColorPicker.mqh | class=class="str">"cmt">//| Copyright class="num">2015, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "Element.mqh" class="macro">#include "Window.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 用于创建颜色选择器的类 | class=class="str">"cmt">//+------------------------------------------------------------------+ class CColorPicker : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 控件所附加的表单的指针 CWindow *m_wnd; class=class="str">"cmt">//--- class="kw">public: CColorPicker(class="type">void); ~CColorPicker(class="type">void); class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 保存表单的指针 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(class="kw">const class="type">int id,class="kw">const class="type">long &lparam,class="kw">const class="type">class="kw">double &dparam,class="kw">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(class="kw">const class="type">int x,class="kw">const class="type">int y); class=class="str">"cmt">//--- (class="num">1) 显示, (class="num">2) 隐藏, (class="num">3) 重置, (class="num">4) 删除
调色板控件的虚接口与配色成员
在 MT5 自定义 GUI 库里,颜色选择器基类先声明了一批 virtual 方法,用来接管显示、隐藏与层级控制。Show()、Hide()、Reset()、Delete() 四个虚函数给子类留了重写入口,而 SetZorders() / ResetZorders() 专门处理鼠标左键点击优先级——注释里标了 (1) 设置、(2) 重设,说明运行时可能动态改命中顺序。 紧跟着的 CColorPicker 私有段只放颜色状态:m_area_color 管区域底色,m_area_border_color 管区域边框,m_palette_border_color 管调色板外框。这三个成员没有默认值,不调用 AreaBackColor() 之类接口就全是黑(0x000000)。 公开侧三个 setter 都是单行内联:AreaBackColor(const color clr) 直接把入参塞进 m_area_color,AreaBorderColor 与 PaletteBorderColor 同理。复制下面这段就能在 EA 里改调色板配色,外汇与贵金属图表挂此类控件仍属高风险界面实验,建议先在策略测试器里验证。 另一个同名 CColorPicker 类则聚合了 CRectLabel、CRectCanvas 与 CRadioButtons 等子对象,m_area / m_canvas / m_current / m_picked / m_hover 五个标签加一个单选组,构成实际可交互的取色面板。头文件依赖里被高亮的 SpinEdit.mqh、SimpleButton.mqh、RadioButtons.mqh 正是面板数值与按钮交互的底层。
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 CColorPicker : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- (class="num">1) 区域 和 (class="num">2)区域边框的颜色 class="type">color m_area_color; class="type">color m_area_border_color; class=class="str">"cmt">//--- 调色板边框的颜色 class="type">color m_palette_border_color; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 设置颜色 (class="num">1) 区域 (class="num">2) 区域边框 (class="num">3) 调色板边框 class="type">void AreaBackColor(class="kw">const class="type">color clr) { m_area_color=clr; } class="type">void AreaBorderColor(class="kw">const class="type">color clr) { m_area_border_color=clr; } class="type">void PaletteBorderColor(class="kw">const class="type">color clr) { m_palette_border_color=clr; } }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//| ColorPicker.mqh | class=class="str">"cmt">//| Copyright class="num">2015, MetaQuotes Software Corp. | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#include "Element.mqh" class="macro">#include "Window.mqh" class="macro">#include "SpinEdit.mqh" class="macro">#include "SimpleButton.mqh" class="macro">#include "RadioButtons.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 用于创建颜色调色板的类 | class=class="str">"cmt">//+------------------------------------------------------------------+ class CColorPicker : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 用于创建控件的对象 CRectLabel m_area; CRectCanvas m_canvas; CRectLabel m_current; CRectLabel m_picked; CRectLabel m_hover; class=class="str">"cmt">//--- CRadioButtons m_radio_buttons;
「颜色选择器类的控件与私有数据声明」
在 MT5 自定义指标或 EA 的面板开发里,做一个取色器得先把界面控件和底层数值分开挂。下面这段类内声明把 HSL、RGB、Lab 三种模型的微调框各自用 CSpinEdit 实例接管,再配两个 CSimpleButton 收口确认与取消。 CSpinEdit m_hsl_h_edit; CSpinEdit m_hsl_s_edit; CSpinEdit m_hsl_l_edit; //--- 分隔注释 CSpinEdit m_rgb_r_edit; CSpinEdit m_rgb_g_edit; CSpinEdit m_rgb_b_edit; //--- 分隔注释 CSpinEdit m_lab_l_edit; CSpinEdit m_lab_a_edit; CSpinEdit m_lab_b_edit; //--- 分隔注释 CSimpleButton m_button_ok; CSimpleButton m_button_cancel; 上面每块 CSpinEdit 对应一种颜色分量,比如 m_hsl_h_edit 管色相、m_rgb_r_edit 管红通道;注释行只是代码分区,不影响编译。 public 下只暴露一个 CreateColorPicker(),接收 chart_id、subwin、x、y 四个参数,负责把整个拾色面板画到指定图表子窗口坐标。private 里则有一长串 CreateXxx 方法,从 CreateArea、CreatePalette 到 CreateHslHEdit、CreateRgbREdit 等,分别构造调色板区域、当前色块、悬停色块和各个数字框。 类尾部又声明了 double 型的 m_hsl_h、m_hsl_s、m_hsl_l、m_rgb_r 等私有变量,这才是真正存颜色分量数值的地方。控件只负责显示和输入,数值变更后由这些变量参与后续色空间转换逻辑。 开 MT5 新建一个面板类时,照这个结构把 9 个 CSpinEdit 和 2 个按钮先声明出来,编译能过再去补 Create 方法体,避免一边写逻辑一边改成员清单。
CSpinEdit m_hsl_h_edit; CSpinEdit m_hsl_s_edit; CSpinEdit m_hsl_l_edit; class=class="str">"cmt">//--- CSpinEdit m_rgb_r_edit; CSpinEdit m_rgb_g_edit; CSpinEdit m_rgb_b_edit; class=class="str">"cmt">//--- CSpinEdit m_lab_l_edit; CSpinEdit m_lab_a_edit; CSpinEdit m_lab_b_edit; class=class="str">"cmt">//--- CSimpleButton m_button_ok; CSimpleButton m_button_cancel; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 用于创建控件的方法 class="type">bool CreateColorPicker(class="kw">const class="type">long chart_id,class="kw">const class="type">int subwin,class="kw">const class="type">int x,class="kw">const class="type">int y); class=class="str">"cmt">//--- class="kw">private: class="type">bool CreateArea(class="type">void); class="type">bool CreatePalette(class="type">void); class="type">bool CreateCurrentSample(class="type">void); class="type">bool CreatePickedSample(class="type">void); class="type">bool CreateHoverSample(class="type">void); class="type">bool CreateRadioButtons(class="type">void); class="type">bool CreateHslHEdit(class="type">void); class="type">bool CreateHslSEdit(class="type">void); class="type">bool CreateHslLEdit(class="type">void); class="type">bool CreateRgbREdit(class="type">void); class="type">bool CreateRgbGEdit(class="type">void); class="type">bool CreateRgbBEdit(class="type">void); class="type">bool CreateLabLEdit(class="type">void); class="type">bool CreateLabAEdit(class="type">void); class="type">bool CreateLabBEdit(class="type">void); class="type">bool CreateButtonOK(class="kw">const class="type">class="kw">string text); class="type">bool CreateButtonCancel(class="kw">const class="type">class="kw">string text); }; class CColorPicker : class="kw">public CElement { class="kw">private: class=class="str">"cmt">//--- 不同颜色模型的组成部份的数值: class=class="str">"cmt">// HSL class="type">class="kw">double m_hsl_h; class="type">class="kw">double m_hsl_s; class="type">class="kw">double m_hsl_l; class=class="str">"cmt">//--- RGB class="type">class="kw">double m_rgb_r;