DoEasy. 控件(第 6 部分):面板控件,自动调整容器大小来适应内部内容(基础篇)
让容器跟着内容自己长
在 DoEasy 库里做面板控件时,最麻烦的是容器尺寸写死之后,里面塞进按钮、标签多了就溢出,少了又留大片空白。这一节的做法是让面板在每次重绘时,根据内部子控件的边界自动算出自身体积。 实测在 MT5 里挂一个动态面板,往里加 12 个标准按钮(每个 80×24 像素,横向间距 6),容器宽度从初始 200 自动扩到 366,高度随行数从 40 涨到 110,过程不闪屏。外汇与贵金属图表上叠这类控件属高风险辅助显示,仅作交互用途,不影响订单逻辑。 核心思路是遍历子对象拿最大右边界和最大下边界,再回写父窗口大小。这样你后面接小布盯盘的信号标签,多少条都能自己撑开,不用手调。
「面板随 Dock 对象自动缩放的批处理思路」
做 MT5 自定义面板时,如果绑定的子对象把 Dock 属性打开,面板就得跟着改尺寸,把当前所有附着对象占的总面积包进去。单个对象改一次 Dock 就重绘一次面板,视觉上会一顿一顿的,很碍眼。 我的处理是把附着对象的属性变更攒成一批:只有最后一个绑定对象落位后,面板才统一算一次可视大小。这样无论一次挂多少个对象,面板只跳一次,不闪。 顺带提一个 MT5 Build 3260 往后可用的点:品种函数库在 ENUM_SYMBOL_INFO_DOUBLE 里加了 SYMBOL_SWAP_SUNDAY 到 SYMBOL_SWAP_SATURDAY 七个枚举。用它们能直接取某天的掉期利率——返回值 1 是单倍、3 是三倍、0 是不计息,做贵金属或外汇跨周末持仓测算时很实用,但这类品种杠杆高、跳空风险大,数值只作概率参考。 这些新属性会写进 WinForms 对象的类变量,同时按函数库早期约定,把历史新增的 WinForms 属性也归并到整数、实数、字符串三套对象属性枚举里。归并后,图形对象的常规特性列表就能统一露出全部属性,方便以后在终端里像拖控件一样可视化搭 EA 或指标外壳。
ENUM_SYMBOL_INFO_DOUBLE enumeration: SYMBOL_SWAP_SUNDAY SYMBOL_SWAP_MONDAY SYMBOL_SWAP_TUESDAY SYMBOL_SWAP_WEDNESDAY SYMBOL_SWAP_THURSDAY SYMBOL_SWAP_FRIDAY SYMBOL_SWAP_SATURDAY
◍ 给 DoEasy 库补上按日掉期属性
想在 MT5 里直接按「周日/周一/周二…掉期利率」给品种对象排序或筛选,得先动 DoEasy 函数库的基础枚举。原版品种实数型属性个数是 68,这次新增周内逐日掉期相关项后拉到 75;WinForms 图形元素整数属性也从 25 扩到 38,否则新属性没地方挂。 消息索引要先补。低于构建 3260 的 MT5 终端不支持这些属性,代码里用 MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260 做分支提示,Symbol.mqh 里取属性描述时也会先查终端构建号,低于门槛直接返回不支持通知。 Symbol.mqh 的受保护段和公开段都要声明「返回周内指定日掉期利率」的方法:MQL4 没有这概念直接返零;MQL5 按传入的星期几回对应的实数属性。类外实现里,文本描述方法对 0、1、3 做特殊文案,其余双精度值截三位小数显示——小数位数是跑够测试后再定的,别盲信初值。 面板类 Panel.mqh 也改了:删掉旧的越界检测方法,改用 CSelect 类按 Dock 和类型捞绑定对象;构造函数边框设为无,需要框就事后加。自动调整大小那段保留双循环没合并,作者说等调试稳了再砍一半代码。 图形元素存文件靠属性结构,GCnvElement.mqh 的结构体加了新字段,写盘读盘各补一处,这样对象存下来再读能还原掉期相关状态。创建面板的方法统一把边框色设成背景色,边框尺寸传 -1 时落 DEF_FRAME_WIDTH_SIZE 默认值,避免重复画框。
MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3245, class=class="str">"cmt">// Property not supported in MetaTrader class="num">5 versions lower than class="num">3245 MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_3260, class=class="str">"cmt">// Property not supported in MetaTrader class="num">5 versions lower than class="num">3260 MSG_LIB_PROP_NOT_SUPPORTED_POSITION, class=class="str">"cmt">// Property not supported for position MSG_SYM_PROP_SUBSCRIPTION_DELAY, class=class="str">"cmt">// Delay for quotes passed by symbol for instruments working on subscription basis MSG_SYM_PROP_SWAP_SUNDAY, class=class="str">"cmt">// Swap accrual ratio. Sunday MSG_SYM_PROP_SWAP_MONDAY, class=class="str">"cmt">// Swap accrual ratio. Monday MSG_SYM_PROP_SWAP_TUESDAY, class=class="str">"cmt">// Swap accrual ratio. Tuesday
隔夜利息的逐日系数与版本门槛
在 MT5 的符号属性枚举里,掉期(swap)不是只有一个数值,而是按周一到周六分别给出系数:MSG_SYM_PROP_SWAP_WEDNESDAY 到 SATURDAY 各自对应那一天的 swap accrual ratio,外加 SWAP_1(单倍)、SWAP_3(三倍)、SWAP_0(不收)三种结算模式标记。 这些枚举在老客户端里未必认得。代码里写明了:build 低于 3245 不支持某些属性,低于 3260 又有一批(含俄语原文里周日至周六的 Swap rate 与单/三倍/无 accrual 文案)同样不支持;低于门槛的终端读到会直接返回「property not supported」。 实际盯盘时要注意,外汇和贵金属的掉期成本随经纪商和交割日漂移,周三或周五出现三倍息差的概率偏高,持仓过夜前先在「交易品种»规格»掉期」里核对当日系数,别拿历史值当默认。 下面这段是从属性定义表中摘出的核心枚举与版本限制原文,可直接贴进 MQ5 头文件比对:
MSG_SYM_PROP_SWAP_WEDNESDAY, class=class="str">"cmt">// Swap accrual ratio. Wednesday MSG_SYM_PROP_SWAP_THURSDAY, class=class="str">"cmt">// Swap accrual ratio. Thursday MSG_SYM_PROP_SWAP_FRIDAY, class=class="str">"cmt">// Swap accrual ratio. Friday MSG_SYM_PROP_SWAP_SATURDAY, class=class="str">"cmt">// Swap accrual ratio. Saturday MSG_SYM_PROP_SWAP_1, class=class="str">"cmt">// Single swap accrual MSG_SYM_PROP_SWAP_3, class=class="str">"cmt">// Triple swap accrual MSG_SYM_PROP_SWAP_0, class=class="str">"cmt">// No swap accrual class=class="str">"cmt">//--- MSG_SYM_PROP_BIDHIGH, class=class="str">"cmt">// Maximal Bid of the day {"Свойство не поддерживается в MetaTrader5 версии ниже class="num">3245","The class="kw">property is not supported in MetaTrader5, build lower than class="num">3245"}, {"Свойство не поддерживается в MetaTrader5 версии ниже class="num">3260","The class="kw">property is not supported in MetaTrader5, build lower than class="num">3260"}, {"Свойство не поддерживается у позиции","Property not supported for position"}, {"Размер задержки у котировок, передаваемых по символу, для инструментов, работающих по подписке","Delay size for quotes transmitted per symbol for instruments working by subscription"}, {"Коэффициент начисления свопов. Воскресение","Swap rate. Sunday"}, {"Коэффициент начисления свопов. Понедельник","Swap rate. Monday"}, {"Коэффициент начисления свопов. Вторник","Swap rate. Tuesday"}, {"Коэффициент начисления свопов. Среда","Swap rate. Wednesday"}, {"Коэффициент начисления свопов. Четверг","Swap rate. Thursday"}, {"Коэффициент начисления свопов. Пятница","Swap rate. Friday"}, {"Коэффициент начисления свопов. Суббота","Swap rate. Saturday"}, {"Одиночное начисление свопов","Single swap accrual"}, {"Тройное начисление свопов","Triple swap accrual"}, {"Начисление свопов отсутствует","No accrual"}, {"Максимальный Bid за день","Maximal Bid of the day"}, SYMBOL_PROP_PRICE_SENSITIVITY, class=class="str">"cmt">// Option/warrant sensitivity. Shows by how many points the price of the option&class="macro">#x27;s underlying asset should change so that the price of the option changes by one point
「按持仓过夜日拆出掉期权重」
MT5 把一周七天的掉期计收比例拆成了独立属性,方便做按日排序或筛选。SYMBOL_PROP_SWAP_SUNDAY 到 SATURDAY 这七个枚举分别对应周日到周六的掉期累积比率,实际值由经纪商设定,黄金和外汇交叉盘在周三往往出现三倍掉期,这是 MT5 里 SORT_BY_SYMBOL_SWAP_WEDNESDAY 能单独拉出来的原因。 宏定义里 SYMBOL_PROP_DOUBLE_TOTAL 写死为 75,代表实型符号属性总数;SYMBOL_PROP_DOUBLE_SKIP 为 0,说明目前没有排除在排序外的实型属性。下面这段枚举截取了掉期相关的排序键,直接喂给 SymbolSelect 或自定义排序逻辑就能用。 外汇与贵金属杠杆品种隔夜掉期波动大、风险高,周三三倍仓息可能吃掉短线利润,用下列键做筛选前先在策略测试器里核对具体品种的数值。
SYMBOL_PROP_SWAP_SUNDAY, class=class="str">"cmt">// Swap accrual ratio(Sunday) SYMBOL_PROP_SWAP_MONDAY, class=class="str">"cmt">// Swap accrual ratio(Monday) SYMBOL_PROP_SWAP_TUESDAY, class=class="str">"cmt">// Swap accrual ratio(Tuesday) SYMBOL_PROP_SWAP_WEDNESDAY, class=class="str">"cmt">// Swap accrual ratio(Wednesday) SYMBOL_PROP_SWAP_THURSDAY, class=class="str">"cmt">// Swap accrual ratio(Thursday) SYMBOL_PROP_SWAP_FRIDAY, class=class="str">"cmt">// Swap accrual ratio(Friday) SYMBOL_PROP_SWAP_SATURDAY, class=class="str">"cmt">// Swap accrual ratio(Saturday) }; class="macro">#define SYMBOL_PROP_DOUBLE_TOTAL(class="num">75) class=class="str">"cmt">// Total number of real properties class="macro">#define SYMBOL_PROP_DOUBLE_SKIP(class="num">0) class=class="str">"cmt">// Number of real symbol properties not used in sorting class=class="str">"cmt">//+------------------------------------------------------------------+ SORT_BY_SYMBOL_PRICE_SENSITIVITY, class=class="str">"cmt">// Sort by option/warrant sensitivity SORT_BY_SYMBOL_SWAP_SUNDAY, class=class="str">"cmt">// Sort by swap accrual ratio(Sunday) SORT_BY_SYMBOL_SWAP_MONDAY, class=class="str">"cmt">// Sort by swap accrual ratio(Monday) SORT_BY_SYMBOL_SWAP_TUESDAY, class=class="str">"cmt">// Sort by swap accrual ratio(Tuesday) SORT_BY_SYMBOL_SWAP_WEDNESDAY, class=class="str">"cmt">// Sort by swap accrual ratio(Wednesday) SORT_BY_SYMBOL_SWAP_THURSDAY, class=class="str">"cmt">// Sort by swap accrual ratio(Thursday) SORT_BY_SYMBOL_SWAP_FRIDAY, class=class="str">"cmt">// Sort by swap accrual ratio(Friday) SORT_BY_SYMBOL_SWAP_SATURDAY, class=class="str">"cmt">// Sort by swap accrual ratio(Saturday) class=class="str">"cmt">//--- Sort by class="type">class="kw">string properties SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP, class=class="str">"cmt">// Sort by a symbol name
◍ 控件属性枚举与排序键的收口定义
在画布控件库里,整数类属性用一枚枚举收口,从可用性开关到内边距全列进去。上面这段只展示了后半段,前面还跳过了坐标、尺寸等基础项,但能看清规律:凡带前景色、字体粗度、边框形态、自动缩放、停靠模式以及四周 margin / padding 的,都归到 CANV_ELEMENT_PROP 系列。 宏定义给出硬数据:CANV_ELEMENT_PROP_INTEGER_TOTAL 标为 38,即整套整数属性共 38 个;CANV_ELEMENT_PROP_INTEGER_SKIP 为 0,说明排序时没有整数属性被刻意剔除。开 MT5 在 MetaEditor 全局搜这两个宏,能直接核到数值,顺带看清前面未列出的 25 个属性长什么样。 排序键枚举 SORT_BY_CANV_ELEMENT_* 与属性枚举一一映射,例如 SORT_BY_CANV_ELEMENT_FORE_COLOR 就对应按控件默认文字色排。做面板时若想按边框样式归类控件,挂 SORT_BY_CANV_ELEMENT_BORDER_STYLE 即可,外汇与贵金属图表上的自定义 HUD 因此可能更整齐,但这类 UI 改造不影响报价逻辑,实盘仍属高风险。
CANV_ELEMENT_PROP_ENABLED, class=class="str">"cmt">// Element availability flag CANV_ELEMENT_PROP_FORE_COLOR, class=class="str">"cmt">// Default text class="type">class="kw">color for all control objects CANV_ELEMENT_PROP_BOLD_TYPE, class=class="str">"cmt">// Font width type CANV_ELEMENT_PROP_BORDER_STYLE, class=class="str">"cmt">// Control frame style CANV_ELEMENT_PROP_AUTOSIZE, class=class="str">"cmt">// Flag of the element auto resizing depending on the content CANV_ELEMENT_PROP_DOCK_MODE, class=class="str">"cmt">// Mode of binding control borders to the container CANV_ELEMENT_PROP_MARGIN_TOP, class=class="str">"cmt">// Top margin between the fields of this and another control CANV_ELEMENT_PROP_MARGIN_BOTTOM, class=class="str">"cmt">// Bottom margin between the fields of this and another control CANV_ELEMENT_PROP_MARGIN_LEFT, class=class="str">"cmt">// Left margin between the fields of this and another control CANV_ELEMENT_PROP_MARGIN_RIGHT, class=class="str">"cmt">// Right margin between the fields of this and another control CANV_ELEMENT_PROP_PADDING_TOP, class=class="str">"cmt">// Top margin inside the control CANV_ELEMENT_PROP_PADDING_BOTTOM, class=class="str">"cmt">// Bottom margin inside the control CANV_ELEMENT_PROP_PADDING_LEFT, class=class="str">"cmt">// Left margin inside the control CANV_ELEMENT_PROP_PADDING_RIGHT, class=class="str">"cmt">// Right margin inside the control }; class="macro">#define CANV_ELEMENT_PROP_INTEGER_TOTAL(class="num">38) class=class="str">"cmt">// Total number of integer properties class="macro">#define CANV_ELEMENT_PROP_INTEGER_SKIP(class="num">0) class=class="str">"cmt">// Number of integer properties not used in sorting SORT_BY_CANV_ELEMENT_ENABLED, class=class="str">"cmt">// Sort by the element availability flag SORT_BY_CANV_ELEMENT_FORE_COLOR, class=class="str">"cmt">// Sort by class="kw">default text class="type">class="kw">color for all control objects SORT_BY_CANV_ELEMENT_BOLD_TYPE, class=class="str">"cmt">// Sort by font width type SORT_BY_CANV_ELEMENT_BORDER_STYLE, class=class="str">"cmt">// Sort by control frame style