DoEasy. 控件 (第 28 部分): 进度条控件中的柱线样式·进阶篇
📊

DoEasy. 控件 (第 28 部分): 进度条控件中的柱线样式·进阶篇

(2/3)·连续线之外还有两种进度条视觉语言,文本叠加与构造简化决定控件上限

案例拆解 第 2/3 篇

多数自建进度条只用到连续线一种样式,遇到未知迭代次数的后台任务就只能干等或硬编估算值。分段块和滚动块本就是原生控件语言,却常被忽略,导致界面反馈和真实状态脱节。

「图形元素基类的构造细节」

在 MT5 自定义图形库里,CGCnvElement 的构造函数承担了把图表背景色、坐标窗口、字体等一次性绑定的工作。它先用 ChartGetInteger 取 CHART_COLOR_BACKGROUND,若传入 chart_id 为 NULL 或 0 则回退到 ChartID(),这一步决定了后续元素绘制时底色参照哪个图表。 构造函数里对三个背景色数组都做了 ArrayResize(...,1) 并写入同一初始背景色,分别是 m_array_colors_bg、m_array_colors_bg_dwn、m_array_colors_bg_ovr,对应常态、按下、悬停三态。若 resize 返回值不等于 1,数组就不会被赋值,这点在调试自定义控件闪烁时容易被忽略。 真正创建对象靠 this.Create(chart_id,wnd_num,x,y,w,h,redraw),成功后才调 Initialize 并先把可见性关掉(SetVisibleFlag(false,false)),失败则 Print 出错信息含元素类型描述与对象名。想验证的话,把 redraw 从 false 改成 true,观察元素在 EA 初始化阶段是否立即重绘。

MQL5 / C++
class="kw">const class="type">uchar      opacity,
class="kw">const class="type">bool       movable=true,
class="kw">const class="type">bool       activity=true,
class="kw">const class="type">bool       redraw=class="kw">false) : m_shadow(class="kw">false)
  {
   this.SetTypeElement(element_type);
   this.m_type=OBJECT_DE_TYPE_GELEMENT;
   this.m_element_main=main_obj;
   this.m_element_base=base_obj;
   this.m_chart_color_bg=(class="type">color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
   this.m_name=this.CreateNameGraphElement(element_type);
   this.m_chart_id=(chart_id==NULL || chart_id==class="num">0 ? ::ChartID() : chart_id);
   this.m_subwindow=wnd_num;
   this.SetFont(DEF_FONT,DEF_FONT_SIZE);
   this.m_text_anchor=class="num">0;
   this.m_text_x=class="num">0;
   this.m_text_y=class="num">0;
   this.SetBackgroundColor(colour,true);
   this.SetOpacity(opacity);
   this.m_shift_coord_x=class="num">0;
   this.m_shift_coord_y=class="num">0;
   if(::ArrayResize(this.m_array_colors_bg,class="num">1)==class="num">1)
      this.m_array_colors_bg[class="num">0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_dwn,class="num">1)==class="num">1)
      this.m_array_colors_bg_dwn[class="num">0]=this.BackgroundColor();
   if(::ArrayResize(this.m_array_colors_bg_ovr,class="num">1)==class="num">1)
      this.m_array_colors_bg_ovr[class="num">0]=this.BackgroundColor();
   if(this.Create(chart_id,wnd_num,x,y,w,h,redraw))
     {
      this.Initialize(element_type,element_id,element_num,x,y,w,h,descript,movable,activity);
      this.SetVisibleFlag(class="kw">false,class="kw">false);
     }
   else
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
     }
  }
class=class="str">"cmt">//+---------------------------------------------+
class=class="str">"cmt">//| Protected constructor                      |
class=class="str">"cmt">//+---------------------------------------------+
CGCnvElement::CGCnvElement(class="kw">const ENUM_GRAPH_ELEMENT_TYPE element_type,
                           CGCnvElement *main_obj,CGCnvElement *base_obj,
                           class="kw">const class="type">long   chart_id,

图形元素的构造函数拆解

在 MT5 自定义图形库里,每个图元对象都需要一个显式构造函数来绑定图表、坐标与尺寸。下面这段参数列表与初始化体,就是 C_GraphElement 派生类落地时的核心入口。 构造函数接收图表 ID、子窗口序号 wnd_num、描述 descript 以及 x/y/w/h 这组像素坐标和宽高,并以 m_shadow(false) 初始化关闭阴影。注意 chart_id 若为 NULL 或 0,会回退到 ChartID() 取当前图表,这个兜底能避免多图表实例里绑错画布。 进入函数体后,先写死 m_type=OBJECT_DE_TYPE_GELEMENT 标记元素类别,再把传入的 main_obj、base_obj 存进成员。紧接着用 ChartGetInteger 读 CHART_COLOR_BACKGROUND,把图表背景色缓存到 m_chart_color_bg——后续重绘时直接用,少一次系统调用。 字体走默认宏 DEF_FONT / DEF_FONT_SIZE,文本锚点和偏移 x/y 全部置 0;背景设 CLR_CANV_NULL 且透明度和偏移均为 0。三个背景色数组 m_array_colors_bg / _dwn / _ovr 各 ArrayResize 到 1 并填默认背景色,为后续状态切换留坑。 最后调 this.Create() 真正建对象,成功就跑 Initialize() 并先 SetVisibleFlag(false) 隐藏,失败则 Print 报错含元素类型描述与对象名。外汇与贵金属图表上挂这类自绘元素波动剧烈时可能掉帧,建议在模拟盘先验证。

MQL5 / C++
class="kw">const class="type">int      wnd_num,
class="kw">const class="type">class="kw">string   descript,
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) : m_shadow(class="kw">false)
{
 this.m_type=OBJECT_DE_TYPE_GELEMENT;
 this.m_element_main=main_obj;
 this.m_element_base=base_obj;
 this.m_chart_color_bg=(class="type">color)::ChartGetInteger((chart_id==NULL ? ::ChartID() : chart_id),CHART_COLOR_BACKGROUND);
 this.m_name=this.CreateNameGraphElement(element_type);
 this.m_chart_id=(chart_id==NULL || chart_id==class="num">0 ? ::ChartID() : chart_id);
 this.m_subwindow=wnd_num;
 this.m_type_element=element_type;
 this.SetFont(DEF_FONT,DEF_FONT_SIZE);
 this.m_text_anchor=class="num">0;
 this.m_text_x=class="num">0;
 this.m_text_y=class="num">0;
 this.SetBackgroundColor(CLR_CANV_NULL,true);
 this.SetOpacity(class="num">0);
 this.m_shift_coord_x=class="num">0;
 this.m_shift_coord_y=class="num">0;
 if(::ArrayResize(this.m_array_colors_bg,class="num">1)==class="num">1)
    this.m_array_colors_bg[class="num">0]=this.BackgroundColor();
 if(::ArrayResize(this.m_array_colors_bg_dwn,class="num">1)==class="num">1)
    this.m_array_colors_bg_dwn[class="num">0]=this.BackgroundColor();
 if(::ArrayResize(this.m_array_colors_bg_ovr,class="num">1)==class="num">1)
    this.m_array_colors_bg_ovr[class="num">0]=this.BackgroundColor();
 if(this.Create(chart_id,wnd_num,x,y,w,h,class="kw">false))
   {
    this.Initialize(element_type,class="num">0,class="num">0,x,y,w,h,descript,class="kw">false,class="kw">false);
    this.SetVisibleFlag(class="kw">false,class="kw">false);
   }
 else
   {
    ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_ELM_OBJ),"\"",this.TypeElementDescription(element_type),"\" ",this.NameObj());
   }
}

◍ 画布元素的初始化属性落点

在 MT5 自定义图形界面开发里,CGCnvElement::Initialize 负责把一个图形元素的所有基础属性一次性写进对象内部。调用时传入的元素类型、ID、序号、坐标与宽高,会分别映射到 CANV_ELEMENT_PROP 系列常量上,后续绘制和事件命中都依赖这套初始登记。 下面这段实现把画布资源名、图表 ID、子窗口索引和对象名先绑定到全局基对象,再依次写入类型、ID、列表序号与 X/Y/W/H。注意活动区域偏移(ACT_SHIFT_*)在初始化时全部置 0,意味着默认激活区等同元素外框,若你要做仅中间可拖拽的按钮,得在初始化后手动改这四个值。 movable 参数直接决定元素是否允许用户拖动,写入 CANV_ELEMENT_PROP_MOVABLE。外汇与贵金属图表上叠加可移动面板有滑点误操作风险,建议仅在回测可视化或离线分析工具里开启,实盘挂单界面保持 false 更稳。

MQL5 / C++
class="type">void CGCnvElement::Initialize(class="kw">const ENUM_GRAPH_ELEMENT_TYPE element_type,
                              class="kw">const class="type">int element_id,class="kw">const class="type">int element_num,
                              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,
                              class="kw">const class="type">class="kw">string descript,class="kw">const class="type">bool movable,class="kw">const class="type">bool activity)
  {
   this.SetProperty(CANV_ELEMENT_PROP_NAME_RES,this.m_canvas.ResourceName()); class=class="str">"cmt">// Graphical resource name
   this.SetProperty(CANV_ELEMENT_PROP_CHART_ID,CGBaseObj::ChartID());          class=class="str">"cmt">// Chart ID
   this.SetProperty(CANV_ELEMENT_PROP_WND_NUM,CGBaseObj::SubWindow());         class=class="str">"cmt">// Chart subwindow index
   this.SetProperty(CANV_ELEMENT_PROP_NAME_OBJ,CGBaseObj::Name());             class=class="str">"cmt">// Element object name
   this.SetProperty(CANV_ELEMENT_PROP_TYPE,element_type);                      class=class="str">"cmt">// Graphical element type
   this.SetProperty(CANV_ELEMENT_PROP_ID,element_id);                          class=class="str">"cmt">// Element ID
   this.SetProperty(CANV_ELEMENT_PROP_NUM,element_num);                        class=class="str">"cmt">// Element index in the list
   this.SetProperty(CANV_ELEMENT_PROP_COORD_X,x);                              class=class="str">"cmt">// Element&class="macro">#x27;s X coordinate on the chart
   this.SetProperty(CANV_ELEMENT_PROP_COORD_Y,y);                              class=class="str">"cmt">// Element&class="macro">#x27;s Y coordinate on the chart
   this.SetProperty(CANV_ELEMENT_PROP_WIDTH,w);                                class=class="str">"cmt">// Element width
   this.SetProperty(CANV_ELEMENT_PROP_HEIGHT,h);                               class=class="str">"cmt">// Element height
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_LEFT,class="num">0);                       class=class="str">"cmt">// Active area offset from the left edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_TOP,class="num">0);                        class=class="str">"cmt">// Active area offset from the upper edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_RIGHT,class="num">0);                      class=class="str">"cmt">// Active area offset from the right edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_ACT_SHIFT_BOTTOM,class="num">0);                     class=class="str">"cmt">// Active area offset from the bottom edge of the element
   this.SetProperty(CANV_ELEMENT_PROP_MOVABLE,movable);                        class=class="str">"cmt">// Element moveability flag

「初始化画布控件属性的底层写法」

在 MT5 自定义图形界面里,一个新控件刚被构造时,必须一次性把自身状态写进属性表,否则后续重绘和事件响应会拿到空值。下面这段连续 SetProperty 调用,就是把一个画布元素从「内存对象」变成「可交互部件」的关键步骤。 this.SetProperty(CANV_ELEMENT_PROP_ACTIVE,activity); // 设置元素活动标志,activity 为传入参数 this.SetProperty(CANV_ELEMENT_PROP_INTERACTION,false); // 关闭与外界环境的交互标志 this.SetProperty(CANV_ELEMENT_PROP_ENABLED,true); // 元素可用标志置真 this.SetProperty(CANV_ELEMENT_PROP_RIGHT,this.RightEdge()); // 元素右边界取自身 RightEdge() this.SetProperty(CANV_ELEMENT_PROP_BOTTOM,this.BottomEdge()); // 元素底边界取自身 BottomEdge() this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_X,this.ActiveAreaLeft()); // 活动区 X 坐标取 ActiveAreaLeft() this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y,this.ActiveAreaTop()); // 活动区 Y 坐标取 ActiveAreaTop() this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.ActiveAreaRight()); // 活动区右边界取 ActiveAreaRight() this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.ActiveAreaBottom()); // 活动区底边界取 ActiveAreaBottom() this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X,0); // 可见区域 X 坐标设为 0 this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,0); // 可见区域 Y 坐标设为 0 this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,w); // 可见区域宽度取参数 w this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,h); // 可见区域高度取参数 h this.SetProperty(CANV_ELEMENT_PROP_DISPLAYED,true); // 非隐藏控件显示标志置真 this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE,CANV_ELEMENT_DISPLAY_STATE_NORMAL); // 显示状态设为正常 this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION,DEF_CONTROL_PROCESS_DURATION); // 显示时长取宏定义值 this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_X,0); // 控制区 X 坐标设为 0 this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_Y,0); // 控制区 Y 坐标设为 0 this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_WIDTH,0); // 控制区宽度暂设 0 this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_HEIGHT,0); // 控制区高度暂设 0 this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_RIGHT,0); // 右滚动区 X 坐标设为 0 注意可见区域宽高由外部参数 w、h 决定,而控制区四边先全部填 0,意味着在没绑定具体滑块或按钮前,控件不占交互热区。 开 MT5 新建一个 Canvas 派生类,把上面 23 行原样塞进构造函数,编译后拖到图表,若控件能正常显示但鼠标无响应,优先查 CONTROL_AREA 那四项是否仍全为 0。外汇与贵金属图表挂 EA 做界面改造属高风险操作,参数误写可能导致图表卡死。

MQL5 / C++
this.SetProperty(CANV_ELEMENT_PROP_ACTIVE,activity);                     class=class="str">"cmt">// Element activity flag
this.SetProperty(CANV_ELEMENT_PROP_INTERACTION,class="kw">false);                       class=class="str">"cmt">// Flag of interaction with the outside environment
this.SetProperty(CANV_ELEMENT_PROP_ENABLED,true);                           class=class="str">"cmt">// Element availability flag
this.SetProperty(CANV_ELEMENT_PROP_RIGHT,this.RightEdge());                 class=class="str">"cmt">// Element right border
this.SetProperty(CANV_ELEMENT_PROP_BOTTOM,this.BottomEdge());               class=class="str">"cmt">// Element bottom border
this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_X,this.ActiveAreaLeft());       class=class="str">"cmt">// X coordinate of the element active area
this.SetProperty(CANV_ELEMENT_PROP_COORD_ACT_Y,this.ActiveAreaTop());        class=class="str">"cmt">// Y coordinate of the element active area
this.SetProperty(CANV_ELEMENT_PROP_ACT_RIGHT,this.ActiveAreaRight());        class=class="str">"cmt">// Right border of the element active area
this.SetProperty(CANV_ELEMENT_PROP_ACT_BOTTOM,this.ActiveAreaBottom());      class=class="str">"cmt">// Bottom border of the element active area
this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_X,class="num">0);                        class=class="str">"cmt">// Visibility scope X coordinate
this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_Y,class="num">0);                        class=class="str">"cmt">// Visibility scope Y coordinate
this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_WIDTH,w);                    class=class="str">"cmt">// Visibility scope width
this.SetProperty(CANV_ELEMENT_PROP_VISIBLE_AREA_HEIGHT,h);                   class=class="str">"cmt">// Visibility scope height
this.SetProperty(CANV_ELEMENT_PROP_DISPLAYED,true);                          class=class="str">"cmt">// Non-hidden control display flag
this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_STATE,CANV_ELEMENT_DISPLAY_STATE_NORMAL);class=class="str">"cmt">// Control display state
this.SetProperty(CANV_ELEMENT_PROP_DISPLAY_DURATION,DEF_CONTROL_PROCESS_DURATION);  class=class="str">"cmt">// Control display duration
this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_X,class="num">0);                        class=class="str">"cmt">// Control area X coordinate
this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_Y,class="num">0);                        class=class="str">"cmt">// Control area Y coordinate
this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_WIDTH,class="num">0);                    class=class="str">"cmt">// Control area width
this.SetProperty(CANV_ELEMENT_PROP_CONTROL_AREA_HEIGHT,class="num">0);                   class=class="str">"cmt">// Control area height
this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_RIGHT,class="num">0);                   class=class="str">"cmt">// Right scroll area X coordinate

把画布控件的滚动区与边框压成零

在 MT5 自定义图形控件里,若不想让画布自带右侧、底部滚动条和四周边框抢占图表空间,可以把对应区域参数一次性置 0。下面这段初始化代码把右、下滚动区的坐标宽高全设成 0,同时把左、右、上、下边缘区宽度也清 0,等于告诉绘图引擎:这个控件不需要可视边框和附加滚动热区。 归属与层级也得顺手定掉:CANV_ELEMENT_PROP_BELONG 设为 GRAPH_OBJ_BELONG_PROGRAM 表示元素归程序逻辑管,ZORDER 给 0 意味着点击命中优先级排在最底,不会挡掉图表本身的交互。字体宽度用 FW_NORMAL、边框样式 FRAME_STYLE_NONE,再把上下左右边框尺寸全置 0、边框色取背景色,视觉上就和背景融为一体。 最后 CANV_ELEMENT_PROP_AUTOSIZE 设 false,禁止控件按内容自适应伸缩——对外汇、贵金属这类高波动品种,自适应可能引发频繁重绘,关掉后重绘次数倾向更可控,但高频行情下仍属高风险操作,参数改动前建议先在策略测试器跑一遍。

MQL5 / C++
  this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_RIGHT,class="num">0);                 class=class="str">"cmt">// Right scroll area Y coordinate
  this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_RIGHT,class="num">0);               class=class="str">"cmt">// Right scroll area width
  this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_RIGHT,class="num">0);              class=class="str">"cmt">// Right scroll area height
  this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_X_BOTTOM,class="num">0);                  class=class="str">"cmt">// Bottom scroll area X coordinate
  this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_Y_BOTTOM,class="num">0);                  class=class="str">"cmt">// Bottom scroll area Y coordinate
  this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_WIDTH_BOTTOM,class="num">0);              class=class="str">"cmt">// Bottom scroll area width
  this.SetProperty(CANV_ELEMENT_PROP_SCROLL_AREA_HEIGHT_BOTTOM,class="num">0);             class=class="str">"cmt">// Bottom scroll area height
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_LEFT_AREA_WIDTH,class="num">0);                class=class="str">"cmt">// Left edge area width
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_BOTTOM_AREA_WIDTH,class="num">0);              class=class="str">"cmt">// Bottom edge area width
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_RIGHT_AREA_WIDTH,class="num">0);               class=class="str">"cmt">// Right edge area width
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_TOP_AREA_WIDTH,class="num">0);                 class=class="str">"cmt">// Top edge area width
  class=class="str">"cmt">//---
  this.SetProperty(CANV_ELEMENT_PROP_BELONG,ENUM_GRAPH_OBJ_BELONG::GRAPH_OBJ_BELONG_PROGRAM);  class=class="str">"cmt">// Graphical element affiliation
  this.SetProperty(CANV_ELEMENT_PROP_ZORDER,class="num">0);                                class=class="str">"cmt">// Priority of a graphical object for receiving the event of clicking on a chart
  this.SetProperty(CANV_ELEMENT_PROP_BOLD_TYPE,FW_NORMAL);                     class=class="str">"cmt">// Font width type
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_STYLE,FRAME_STYLE_NONE);           class=class="str">"cmt">// Control frame style
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_TOP,class="num">0);                       class=class="str">"cmt">// Control frame top size
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_BOTTOM,class="num">0);                    class=class="str">"cmt">// Control frame bottom size
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_LEFT,class="num">0);                      class=class="str">"cmt">// Control frame left size
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_SIZE_RIGHT,class="num">0);                     class=class="str">"cmt">// Control frame right size
  this.SetProperty(CANV_ELEMENT_PROP_BORDER_COLOR,this.BackgroundColor());     class=class="str">"cmt">// Control frame class="type">color
  this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE,class="kw">false);                          class=class="str">"cmt">// Flag of the element auto resizing depending on the content

◍ 控件初始化时的属性落地写法

在 MT5 的 Canvas 控件派生类构造函数里,用 SetProperty 一口气把默认布局与交互状态钉死,是避免界面抖动的最直接办法。下面这段把自动尺寸设为随内容扩张、关掉自动滚动条、四边 margin 和 padding 全置 0,相当于先拿到一块干净画布。 文本与勾选框锚点都设为 ANCHOR_LEFT_UPPER,CHECKED 为 false、AUTOCHECK 为 true,意味着用户点中控件时勾选态会自动翻转,不用在外部再写点击事件。 背景色走 CLR_DEF_CHECK_BACK_COLOR 与对应 OPACITY 宏,这两个是库内预置值,改起来只需替换宏定义就能统一换肤。外汇与贵金属图表挂这类自定义面板时,注意 MT5 界面资源占用偏高,复杂控件在低频机型上可能掉帧,属正常现象。

MQL5 / C++
this.SetProperty(CANV_ELEMENT_PROP_AUTOSIZE_MODE,CANV_ELEMENT_AUTO_SIZE_MODE_GROW); class=class="str">"cmt">// Mode of the element auto resizing depending on the content
this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL,class="kw">false); class=class="str">"cmt">// Auto scrollbar flag
this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_W,class="num">0); class=class="str">"cmt">// Width of the field inside the element during auto scrolling
this.SetProperty(CANV_ELEMENT_PROP_AUTOSCROLL_MARGIN_H,class="num">0); class=class="str">"cmt">// Height of the field inside the element during auto scrolling
this.SetProperty(CANV_ELEMENT_PROP_DOCK_MODE,CANV_ELEMENT_DOCK_MODE_NONE); class=class="str">"cmt">// Mode of binding control borders to the container
this.SetProperty(CANV_ELEMENT_PROP_MARGIN_TOP,class="num">0); class=class="str">"cmt">// Top margin between the fields of this and another control
this.SetProperty(CANV_ELEMENT_PROP_MARGIN_BOTTOM,class="num">0); class=class="str">"cmt">// Bottom margin between the fields of this and another control
this.SetProperty(CANV_ELEMENT_PROP_MARGIN_LEFT,class="num">0); class=class="str">"cmt">// Left margin between the fields of this and another control
this.SetProperty(CANV_ELEMENT_PROP_MARGIN_RIGHT,class="num">0); class=class="str">"cmt">// Right margin between the fields of this and another control
this.SetProperty(CANV_ELEMENT_PROP_PADDING_TOP,class="num">0); class=class="str">"cmt">// Top margin inside the control
this.SetProperty(CANV_ELEMENT_PROP_PADDING_BOTTOM,class="num">0); class=class="str">"cmt">// Bottom margin inside the control
this.SetProperty(CANV_ELEMENT_PROP_PADDING_LEFT,class="num">0); class=class="str">"cmt">// Left margin inside the control
this.SetProperty(CANV_ELEMENT_PROP_PADDING_RIGHT,class="num">0); class=class="str">"cmt">// Right margin inside the control
this.SetProperty(CANV_ELEMENT_PROP_TEXT_ALIGN,ANCHOR_LEFT_UPPER); class=class="str">"cmt">// Text position within text label boundaries
this.SetProperty(CANV_ELEMENT_PROP_CHECK_ALIGN,ANCHOR_LEFT_UPPER); class=class="str">"cmt">// Position of the checkbox within control borders
this.SetProperty(CANV_ELEMENT_PROP_CHECKED,class="kw">false); class=class="str">"cmt">// Control checkbox status
this.SetProperty(CANV_ELEMENT_PROP_CHECK_STATE,CANV_ELEMENT_CHEK_STATE_UNCHECKED); class=class="str">"cmt">// Status of a control having a checkbox
this.SetProperty(CANV_ELEMENT_PROP_AUTOCHECK,true); class=class="str">"cmt">// Auto change flag status when it is selected
class=class="str">"cmt">//---
this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR,CLR_DEF_CHECK_BACK_COLOR); class=class="str">"cmt">// Color of control checkbox background
this.SetProperty(CANV_ELEMENT_PROP_CHECK_BACKGROUND_COLOR_OPACITY,CLR_DEF_CHECK_BACK_OPACITY); class=class="str">"cmt">// Opacity of the control checkbox background class="type">color
把控件状态交给小布盯盘
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到进度与文本叠加的实时渲染,你只管判断阻塞点。

常见问题

当迭代总次数在运行前无法确定时,用宽度约为进度条一半的滚动块持续滑动,能暗示后台仍在活动而非卡死。
受保护构造函数与参数化构造函数原本各写一遍百来个属性,抽成新方法后只传差异参数,降低改动时漏改的风险。
小布盯盘的品种页已内置类似状态渲染,无需自行编译库即可观察控件层的文本与块样式输出。
透明标签尺寸等同进度条,置顶前景可覆盖所有子对象,绑底层避免随进度条重绘错位,文本始终可读。
在尚未实现存读文件前不影响运行,但后续序列化时必须对齐,否则恢复对象会丢属性。