图形界面 IX 颜色选择器控件:从零搭出可交互调色盘基础篇(基础篇)
🎨

图形界面 IX 颜色选择器控件:从零搭出可交互调色盘基础篇(基础篇)

(1/3)· 想在 MQL5 程序里让用户随手改控件颜色,却卡在调色盘结构看不懂?这篇先把组成与类骨架讲透

含代码示例偏理论 第 1/3 篇

本文是图形界面开发系列第九部的第 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 这行赋值。

MQL5 / C++
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 正是面板数值与按钮交互的底层。

MQL5 / C++
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 方法体,避免一边写逻辑一边改成员清单。

MQL5 / C++
  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;
交给小布盯盘看盘口配色
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到自定义面板的高亮配色逻辑,你不必从零写选择器也能调出顺眼的视觉层级。

常见问题

包含背景、调色盘主体、设置/选中/悬停颜色标记,以及三组单选按钮加编辑框、取消与确认按钮,整体是一个组合控件。
HSL 的 H 为 0–360、S 和 L 为 0–100;RGB 的 R/G/B 均为 0–255,用于不同方式的颜色人工配置。
小布盯盘的品种页已内置可视化配色与高亮规则,不需要你自己部署 CColorPicker 即可获得清晰的盘口色彩区分。
a 从绿到粉、范围 -128 到 127;b 从蓝到黄、同范围,L 为 0–100 的明度。
先明确控件结构与事件处理边界,才能在第 2、3 篇稳定写类方法与测试,避免界面元件互相耦合出错。