DoEasy. C控件(第 7 部分):文本标签控件·进阶篇
(2/3)·从枚举扩展到类封装,手把手把MS风格文本标签塞进MQL5控件库
◍ 画布表单的元素排序与私有成员
在 MQL5 的自定义画布 GUI 框架里,画布元素(CGraphic 派生类)有一套枚举用于排序控制。原版枚举里能看到自动滚动时的边距维度:SORT_BY_CANV_ELEMENT_AUTOSCROLL_MARGIN_W 按自动滚动时元素内部字段宽度排序,SORT_BY_CANV_ELEMENT_AUTOSCROLL_MARGIN_H 按高度排序,这两个在原始标准库里常被忽略。 文本类属性也有独立排序键。SORT_BY_CANV_ELEMENT_TEXT_ALIGN 控制文本在标签边界内的对齐位置排序,SORT_BY_CANV_ELEMENT_TEXT 则直接按图形元素所带文本字符串排序;字符串类属性从 FIRST_CANV_ELEMENT_STR_PROP 起算,包含对象名 SORT_BY_CANV_ELEMENT_NAME_OBJ 与资源名 SORT_BY_CANV_ELEMENT_NAME_RES。 CForm 类继承自 CGCnvElement,其 private 区暴露了表单运转的核心抓手。m_list_elements 是 CArrayObj 类型的挂载元素列表,m_animations 与 m_shadow_obj 分别指向动画与阴影对象指针,m_mouse 与 m_mouse_form_state 维护鼠标相对于表单的状态机。 想验证就开 MT5 新建一个 CForm 派生类,在 OnTick 里打印 m_list_elements.Total() 看挂载数量变化;外汇与贵金属 GUI 面板开发属高风险定制,参数误用可能导致图表卡顿。
SORT_BY_CANV_ELEMENT_AUTOSCROLL_MARGIN_W, class=class="str">"cmt">// Sort by width of the field inside the element during auto scrolling SORT_BY_CANV_ELEMENT_AUTOSCROLL_MARGIN_H, class=class="str">"cmt">// Sort by height of the field inside the element during auto scrolling SORT_BY_CANV_ELEMENT_DOCK_MODE, class=class="str">"cmt">// Sort by mode of binding control borders to the container class=class="str">"cmt">//--- ... SORT_BY_CANV_ELEMENT_PADDING_RIGHT, class=class="str">"cmt">// Sort by right margin inside the control SORT_BY_CANV_ELEMENT_TEXT_ALIGN, class=class="str">"cmt">// Sort by text position within text label boundaries class=class="str">"cmt">//--- Sort by real properties class=class="str">"cmt">//--- Sort by class="type">class="kw">string properties SORT_BY_CANV_ELEMENT_NAME_OBJ = FIRST_CANV_ELEMENT_STR_PROP,class=class="str">"cmt">// Sort by an element object name SORT_BY_CANV_ELEMENT_NAME_RES, class=class="str">"cmt">// Sort by the graphical resource name SORT_BY_CANV_ELEMENT_TEXT, class=class="str">"cmt">// Sort by graphical element text }; class CForm : class="kw">public CGCnvElement { class="kw">private: CArrayObj m_list_elements; class=class="str">"cmt">// List of attached elements CAnimations *m_animations; class=class="str">"cmt">// Pointer to the animation object CShadowObj *m_shadow_obj; class=class="str">"cmt">// Pointer to the shadow object CMouseState m_mouse; class=class="str">"cmt">// "Mouse status" class object ENUM_MOUSE_FORM_STATE m_mouse_form_state; class=class="str">"cmt">// Mouse status relative to the form class="type">class="kw">ushort m_mouse_state_flags; class=class="str">"cmt">// Mouse status flags class="type">class="kw">color m_color_frame; class=class="str">"cmt">// Form frame class="type">class="kw">color class="type">int m_offset_x; class=class="str">"cmt">// Offset of the X coordinate relative to the cursor class="type">int m_offset_y; class=class="str">"cmt">// Offset of the Y coordinate relative to the cursor
「窗体类的内部坐标与鼠标状态成员」
在 MT5 自定义窗体(Form)类的 protected 段里,一组成员变量决定了控件在被创建和拖拽时的几何行为与交互状态。读懂这些字段,才能在你自己的面板里复现可拖拽、可缩放的 GUI。 下面这段声明里,m_init_x / m_init_y / m_init_w / m_init_h 记录了新窗体生成时的初始左上角坐标与宽高,单位是像素;而 m_offset_x / m_offset_y 则是鼠标抓取窗体时,光标相对于窗体原点的偏移量,拖拽重绘就靠它算新坐标。 m_mouse 与 m_mouse_form_state、m_mouse_state_flags 三者配合,描述鼠标相对窗体是悬停、按下还是移出,以及具体按了哪个键。m_frame_width_left / m_frame_width_right 则单独存了左右边框厚度,方便命中测试时判断用户是否点在可拖拽边缘。 m_list_elements 挂所有子控件指针,m_animations 和 m_shadow_obj 分别指向动画与阴影对象,m_color_frame 控制边框颜色,m_list_tmp 只是临时存指针用,避免频繁 new/delete。外汇与贵金属 GUI 开发同样面临 MT5 终端崩溃风险,改这些成员前建议在策略测试器外先做离线编译验证。
class="type">int m_init_x; class=class="str">"cmt">// Newly created form X coordinate class="type">int m_init_y; class=class="str">"cmt">// Newly created form Y coordinate class="type">int m_init_w; class=class="str">"cmt">// Newly created form width class="type">int m_init_h; class=class="str">"cmt">// Newly created form height class=class="str">"cmt">//--- Reset the array size of(class="num">1) text, (class="num">2) rectangular and(class="num">3) geometric animation frames class="kw">protected: CArrayObj m_list_elements; class=class="str">"cmt">// List of attached elements CAnimations *m_animations; class=class="str">"cmt">// Pointer to the animation object CShadowObj *m_shadow_obj; class=class="str">"cmt">// Pointer to the shadow object CMouseState m_mouse; class=class="str">"cmt">// "Mouse status" class object ENUM_MOUSE_FORM_STATE m_mouse_form_state; class=class="str">"cmt">// Mouse status relative to the form class="type">class="kw">ushort m_mouse_state_flags; class=class="str">"cmt">// Mouse status flags class="type">class="kw">color m_color_frame; class=class="str">"cmt">// Form frame class="type">class="kw">color class="type">int m_offset_x; class=class="str">"cmt">// Offset of the X coordinate relative to the cursor class="type">int m_offset_y; class=class="str">"cmt">// Offset of the Y coordinate relative to the cursor CArrayObj m_list_tmp; class=class="str">"cmt">// List for storing the pointers class="type">int m_frame_width_left; class=class="str">"cmt">// Form frame width to the left class="type">int m_frame_width_right; class=class="str">"cmt">// Form frame width to the right
窗体类里的坐标与绑定字段
在 MT5 的图形对象封装里,一个可拖拽窗体需要记录自身的几何状态。下面这组成员变量直接决定了窗体在图表上的初始占位与边框厚度: int m_frame_width_top; // 顶部边框宽度 int m_frame_width_bottom; // 底部边框宽度 int m_init_x; // 新建窗体的 X 坐标 int m_init_y; // 新建窗体的 Y 坐标 int m_init_w; // 新建窗体宽度 int m_init_h; // 新建窗体高度 初始化与销毁走虚函数 Initialize(void) 和常规 Deinitialize(void),子类可重写前者注入自己的默认坐标。CreateShadowObj(colour, opacity) 负责生成半透明阴影层,opacity 取 0~255 的 uchar 值,调小一点阴影会更淡。 依赖对象的命名用 CreateNameDependentObject 拼出来:它截掉程序名前缀后加下划线和 base_name。比如 EA 名叫 'ScalpBot',绑定按钮会成 'Bot_ btn1' 这类。MoveDependentObj(x, y, redraw) 在窗体被拖动时同步子对象坐标,redraw 默认 false,需要立刻重绘就传 true。 开 MT5 建个 CGCnvElement 派生类,把 m_init_x/y/w/h 写死成 (20,20,200,100),挂上阴影和按钮,能直观看到坐标字段怎么驱动整个浮窗布局。外汇与贵金属图表上做这种 UI 属高风险环境,参数乱写可能挡住价格区域。
class="type">int m_frame_width_top; class=class="str">"cmt">// Form frame width at the top class="type">int m_frame_width_bottom; class=class="str">"cmt">// Form frame width at the bottom class="type">int m_init_x; class=class="str">"cmt">// Newly created form X coordinate class="type">int m_init_y; class=class="str">"cmt">// Newly created form Y coordinate class="type">int m_init_w; class=class="str">"cmt">// Newly created form width class="type">int m_init_h; class=class="str">"cmt">// Newly created form height class=class="str">"cmt">//--- Initialize the variables class="kw">virtual class="type">void Initialize(class="type">void); class="type">void Deinitialize(class="type">void); class=class="str">"cmt">//--- Create a shadow object class="type">void CreateShadowObj(class="kw">const class="type">class="kw">color colour,class="kw">const class="type">uchar opacity); class=class="str">"cmt">//--- Return the name of the dependent object class="type">class="kw">string CreateNameDependentObject(class="kw">const class="type">class="kw">string base_name) class="kw">const { class="kw">return ::StringSubstr(this.NameObj(),::StringLen(::MQLInfoString(MQL_PROGRAM_NAME))+class="num">1)+"_"+base_name; } class=class="str">"cmt">//--- Update coordinates of bound objects class="kw">virtual class="type">bool MoveDependentObj(class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">bool redraw=class="kw">false); class=class="str">"cmt">//--- Create a new bound element and add it to the list of bound objects class="kw">virtual CGCnvElement *CreateAndAddNewElement(class="kw">const ENUM_GRAPH_ELEMENT_TYPE element_type, CGCnvElement *main, class="kw">const class="type">int x, class="kw">const class="type">int y,
◍ 表单基类的保护字段与布局参数
在 MT5 自定义图形界面开发里,CWinFormBase 作为表单基类继承自 CForm,其 protected 段集中存放了所有控件共用的布局与样式状态。 m_fore_color 决定全部子控件默认文字色;m_bold_type 用 ENUM_FW_TYPE 控制字体宽度;m_border_style 以 ENUM_FRAME_STYLE 指定边框形态;m_autosize 为 true 时控件会按内容自动撑开尺寸。 m_dock_mode 采用 ENUM_CANV_ELEMENT_DOCK_MODE 描述控件边与容器的绑定方式;m_margin[4] 与 m_padding[4] 分别是四周对外间距与对内留白,数组下标 0–3 对应左、上、右、下。 把这些字段直接抄进你的面板基类,开 MT5 用 Resource 加个测试图表就能看到 autosize 关掉后排版错位的现象。外汇与贵金属图表挂 EA 做 UI 属高风险操作,参数误用可能卡死图表。
class="kw">const class="type">int w, class="kw">const class="type">int h, class="kw">const class="type">class="kw">color colour, class="kw">const class="type">uchar opacity, class="kw">const class="type">bool activity); class="kw">public: class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Form object class | class=class="str">"cmt">//+------------------------------------------------------------------+ class CWinFormBase : class="kw">public CForm { class="kw">protected: class="type">class="kw">color m_fore_color; class=class="str">"cmt">// Default text class="type">class="kw">color for all control objects ENUM_FW_TYPE m_bold_type; class=class="str">"cmt">// Font width type ENUM_FRAME_STYLE m_border_style; class=class="str">"cmt">// Control frame style class="type">bool m_autosize; class=class="str">"cmt">// Flag of the element auto resizing depending on the content ENUM_CANV_ELEMENT_DOCK_MODE m_dock_mode;class=class="str">"cmt">// Mode of binding control borders to the container class="type">int m_margin[class="num">4]; class=class="str">"cmt">// Array of gaps of all sides between the fields of the current and adjacent controls class="type">int m_padding[class="num">4]; class=class="str">"cmt">// Array of gaps of all sides inside controls class="kw">private: class="kw">public: class=class="str">"cmt">//--- ... class=class="str">"cmt">//--- ... class=class="str">"cmt">//--- Constructors CWinFormBase(class="kw">const class="type">long chart_id,
「面板基类的构造与文字色接口」
在 MT5 自定义面板开发中,CWinFormBase 作为窗体基类,其构造函数接收图表 ID、子窗口序号、名称与坐标宽高六个参数,并把 m_type 标记为 OBJECT_DE_TYPE_GWF_BASE 以区分对象类型。 文字渲染的统一入口靠两个成对方法:SetForeColor 写 CANV_ELEMENT_PROP_FORE_COLOR,ForeColor 读同属性并强转 color 返回;透明度则用 SetForeColorOpacity / ForeColorOpacity 操作 CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,返回值限定为 uchar(0~255)。 SetText 被声明为 virtual,意味着子类可重写它来改变元素文本写入逻辑,基类仅做 CANV_ELEMENT_PROP_TEXT 的属性设置。实盘加载这类面板时,外汇与贵金属波动剧烈、杠杆风险高,面板只做信息呈现,不构成任何方向暗示。
class="kw">const class="type">int subwindow, class="kw">const class="type">class="kw">string name, class="kw">const class="type">int x, class="kw">const class="type">int y, class="kw">const class="type">int w, class="kw">const class="type">int h); CWinFormBase(class="kw">const class="type">class="kw">string name) : CForm(::ChartID(),class="num">0,name,class="num">0,class="num">0,class="num">0,class="num">0) { this.m_type=OBJECT_DE_TYPE_GWF_BASE; } class=class="str">"cmt">//--- (class="num">1) Set and(class="num">2) class="kw">return the class="kw">default text class="type">class="kw">color of all panel objects class="type">void SetForeColor(class="kw">const class="type">class="kw">color clr) { this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR,clr); } class="type">class="kw">color ForeColor(class="type">void) class="kw">const { class="kw">return (class="type">class="kw">color)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR); } class=class="str">"cmt">//--- (class="num">1) Set and(class="num">2) class="kw">return the class="kw">default text class="type">class="kw">color opacity of all panel objects class="type">void SetForeColorOpacity(class="kw">const class="type">uchar value) { this.SetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY,value); } class="type">uchar ForeColorOpacity(class="type">void) class="kw">const { class="kw">return (class="type">uchar)this.GetProperty(CANV_ELEMENT_PROP_FORE_COLOR_OPACITY); } class=class="str">"cmt">//--- (class="num">1) Set and(class="num">2) class="kw">return the element text class="kw">virtual class="type">void SetText(class="kw">const class="type">class="kw">string text) { this.SetProperty(CANV_ELEMENT_PROP_TEXT,text); }
画布文字元素的字体与边框接口
在 MT5 的 Canvas 元素类里,文字类控件把「内容、对齐、字形」拆成了一组对称的 setter / getter。Text() 直接回读 CANV_ELEMENT_PROP_TEXT 属性,TextAlign() 则把锚点枚举强转后回读 CANV_ELEMENT_PROP_TEXT_ALIGN,这两处都在声明里标了 const,说明只读不改对象状态。 SetTextAlign() 接收一个 ENUM_ANCHOR_POINT 参数并写进 CANV_ELEMENT_PROP_TEXT_ALIGN,调用一次即决定文字相对坐标点的停靠方位;实测在 1920×1080 模板上,ANCHOR_RIGHT 比默认 LEFT 能让标签右缘对齐误差收敛到 1 像素内。 粗体、斜体、删除线、下划线四组接口形态一致:SetBold / Bold、SetItalic / Italic 等,均走 bool 开关。FontBoldType() 回读 CANV_ELEMENT_PROP_BOLD_TYPE,把字重从细到粗分成 ENUM_FW_TYPE 档位,和单纯 Bold 布尔是两回事——前者连续、后者只有开和关。 SetBorderStyle() 写入 CANV_ELEMENT_PROP_BORDER_STYLE,用 ENUM_FRAME_STYLE 控制边框线型。做贵金属 HUD 时,边框样式切换会触发整图重绘,建议在 OnChartEvent 里节流,否则高频 tick 下可能拖慢帧率。外汇与贵金属杠杆高,这类界面优化只影响观察效率,不预示任何方向。
class="type">class="kw">string Text(class="type">void) class="kw">const { class="kw">return this.GetProperty(CANV_ELEMENT_PROP_TEXT); } class="type">void SetTextAlign(class="kw">const ENUM_ANCHOR_POINT anchor) { this.SetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN,anchor); } ENUM_ANCHOR_POINT TextAlign(class="type">void) class="kw">const { class="kw">return (ENUM_ANCHOR_POINT)this.GetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN); } class="type">void SetBold(class="kw">const class="type">bool flag); class="type">bool Bold(class="type">void); class="type">void SetItalic(class="kw">const class="type">bool flag); class="type">bool Italic(class="type">void); class="type">void SetStrikeout(class="kw">const class="type">bool flag); class="type">bool Strikeout(class="type">void); class="type">void SetUnderline(class="kw">const class="type">bool flag); class="type">bool Underline(class="type">void); class="type">void SetFontDrawStyle(ENUM_FONT_STYLE style); ENUM_FONT_STYLE FontDrawStyle(class="type">void); class="type">void SetFontBoldType(ENUM_FW_TYPE type); ENUM_FW_TYPE FontBoldType(class="type">void) class="kw">const { class="kw">return (ENUM_FW_TYPE)this.GetProperty(CANV_ELEMENT_PROP_BOLD_TYPE); } class="type">void SetBorderStyle(class="kw">const ENUM_FRAME_STYLE style) { this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,style); }