图形界面 IV: 信息界面元件 (第一章)·综合运用
◍ 画布初始化与渐变边框的绘制逻辑
自定义 tooltip 控件的初始化收尾,先把画布背景设为透明(Background(false)),再用 XGap/YGap 把控件左上角对齐到窗口坐标 m_x-m_wnd.X() 与 m_y-m_wnd.Y(),这一步决定了悬浮提示相对主图窗口的偏移量。 渐变数组按 m_y_size 的高度分配,InitColorArray 用顶部色和底部色在 m_array_color 里插值,之后 Erase 以全透明清屏、Update 提交,m_alpha 置 0 代表初始不可见,最后把画布指针塞进元素数组并返回 true。 VerticalGradient 按行画线:x 从 0 到 m_x_size,y 每加 1 取 m_array_color[y] 配 alpha 画一条水平线,纯垂直渐变就是这么一层层叠出来的。 Border 用四组坐标数组画矩形框,x_size/y_size 都减 1 是因为画布像素从 0 计数;四个角各补一个透明黑像素做视觉收口,边角灰点用 C'180,180,180'。外汇与贵金属图表加载这类自绘控件时滑点扩大概率偏高,建议先在模拟盘验证渲染开销。
class="kw">return(false); class=class="str">"cmt">//--- 设置属性 m_canvas.Background(false); class=class="str">"cmt">//--- 到边缘的距离 m_canvas.XGap(m_x-m_wnd.X()); m_canvas.YGap(m_y-m_wnd.Y()); class=class="str">"cmt">//--- 设置工具提示背景渐变色数组的大小 CElement::GradientColorsTotal(m_y_size); ::ArrayResize(m_array_color,m_y_size); class=class="str">"cmt">//--- 初始化渐变色数组 CElement::InitColorArray(m_gradient_top_color,m_gradient_bottom_color,m_array_color); class=class="str">"cmt">//--- 清空画布 m_canvas.Erase(::ColorToARGB(clrNONE,class="num">0)); m_canvas.Update(); m_alpha=class="num">0; class=class="str">"cmt">//--- 保存对象指针 CElement::AddToArray(m_canvas); class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 垂直渐变 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTooltip::VerticalGradient(const class="type">uchar alpha) { class=class="str">"cmt">//--- X 坐标 class="type">int x1=class="num">0; class="type">int x2=m_x_size; class=class="str">"cmt">//--- 画出渐变 for(class="type">int y=class="num">0; y<m_y_size; y++) m_canvas.Line(x1,y,x2,y,::ColorToARGB(m_array_color[y],alpha)); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 边框 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTooltip::Border(const class="type">uchar alpha) { class=class="str">"cmt">//--- 边框颜色 class="type">class="kw">color clr=m_border_color; class=class="str">"cmt">//--- 边界 class="type">int x_size =m_canvas.X_Size()-class="num">1; class="type">int y_size =m_canvas.Y_Size()-class="num">1; class=class="str">"cmt">//--- 坐标: 顶部/右侧/底部/左侧 class="type">int x1[class="num">4]; x1[class="num">0]=class="num">0; x1[class="num">1]=x_size; x1[class="num">2]=class="num">0; x1[class="num">3]=class="num">0; class="type">int y1[class="num">4]; y1[class="num">0]=class="num">0; y1[class="num">1]=class="num">0; y1[class="num">2]=y_size; y1[class="num">3]=class="num">0; class="type">int x2[class="num">4]; x2[class="num">0]=x_size; x2[class="num">1]=x_size; x2[class="num">2]=x_size; x2[class="num">3]=class="num">0; class="type">int y2[class="num">4]; y2[class="num">0]=class="num">0; y2[class="num">1]=y_size; y2[class="num">2]=y_size; y2[class="num">3]=y_size; class=class="str">"cmt">//--- 根据指定坐标画边框 for(class="type">int i=class="num">0; i<class="num">4; i++) m_canvas.Line(x1[i],y1[i],x2[i],y2[i],::ColorToARGB(clr,alpha)); class=class="str">"cmt">//--- 使用一个像素点圆滑边角 clr=clrBlack; m_canvas.PixelSet(class="num">0,class="num">0,::ColorToARGB(clr,class="num">0)); m_canvas.PixelSet(class="num">0,m_y_size-class="num">1,::ColorToARGB(clr,class="num">0)); m_canvas.PixelSet(m_x_size-class="num">1,class="num">0,::ColorToARGB(clr,class="num">0)); m_canvas.PixelSet(m_x_size-class="num">1,m_y_size-class="num">1,::ColorToARGB(clr,class="num">0)); class=class="str">"cmt">//--- 在指定坐标点增加像素点 clr=C&class="macro">#x27;class="num">180,class="num">180,class="num">180&class="macro">#x27;;
提示框的渲染与淡出逻辑
在 MT5 自定义指标里做悬浮提示,核心是把画布(Canvas)当像素缓冲来用。上面这段把边框四角钉死在 (1,1)、(1,m_y_size-2)、(m_x_size-2,1)、(m_x_size-2,m_y_size-2),等于用四个 PixelSet 调用勾出矩形外框,比逐边画线更省开销。 ShowTooltip 先判断 m_alpha>=255 就直接 return,避免重复绘制。标题区固定留给 x=5、y=5,行间距 y_offset=15;若 m_header 非空,主体文字坐标退到 x=15、y=25,否则顶到 x=5、y=5。字体用 FontSet(FONT,-80,...) 负号代表像素高度 80 的竖排尺寸,FW_BLACK 与 FW_THIN 区分标题和正文的粗细。 淡出函数 FadeOutTooltip 用 uchar fadeout_step=7 做透明度步长,从当前 m_alpha 往下减;一旦 a-fadeout_step<0 就强制归零并 Erase 清画布。外汇与贵金属行情跳变快,这种 7/帧 的淡出节奏在 60fps 图表上约 36 帧清完,可据此调 step 匹配你想要的残留时长。 让小布替你跑这套 把 fadeout_step 改成 3 能在 MT5 里明显拖长提示消失过程,适合多文字 tooltip;若做 scalping 快捷提示,调到 12~15 更跟手,但低于 5 容易觉得“黏屏”。
m_canvas.PixelSet(class="num">1,class="num">1,::ColorToARGB(clr,alpha)); m_canvas.PixelSet(class="num">1,m_y_size-class="num">2,::ColorToARGB(clr,alpha)); m_canvas.PixelSet(m_x_size-class="num">2,class="num">1,::ColorToARGB(clr,alpha)); m_canvas.PixelSet(m_x_size-class="num">2,m_y_size-class="num">2,::ColorToARGB(clr,alpha)); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 显示工具提示 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTooltip::ShowTooltip(class="type">void) { class=class="str">"cmt">//--- 如果工具提示100%可见,退出 if(m_alpha>=class="num">255) class="kw">return; class=class="str">"cmt">//--- 标题的坐标和边缘 class="type">int x =class="num">5; class="type">int y =class="num">5; class="type">int y_offset =class="num">15; class=class="str">"cmt">//--- 画出渐变 VerticalGradient(class="num">255); class=class="str">"cmt">//--- 画出边框 Border(class="num">255); class=class="str">"cmt">//--- 画出标题 (如果已指定) if(m_header!="") { class=class="str">"cmt">//--- 设置字体参数 m_canvas.FontSet(FONT,-class="num">80,FW_BLACK); class=class="str">"cmt">//--- 画出标题文字 m_canvas.TextOut(x,y,m_header,::ColorToARGB(m_header_color),TA_LEFT|TA_TOP); } class=class="str">"cmt">//--- 工具提示主体文字的坐标(考虑到标题存在与否) x=(m_header!="")? class="num">15 : class="num">5; y=(m_header!="")? class="num">25 : class="num">5; class=class="str">"cmt">//--- 设置字体参数 m_canvas.FontSet(FONT,-class="num">80,FW_THIN); class=class="str">"cmt">//--- 画出工具提示的主体文字 class="type">int lines_total=::ArraySize(m_tooltip_lines); for(class="type">int i=class="num">0; i<lines_total; i++) { m_canvas.TextOut(x,y,m_tooltip_lines[i],::ColorToARGB(m_text_color),TA_LEFT|TA_TOP); y=y+y_offset; } class=class="str">"cmt">//--- 更新画布 m_canvas.Update(); class=class="str">"cmt">//--- 指出工具提示完全可见 m_alpha=class="num">255; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 工具提示的逐渐淡出 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTooltip::FadeOutTooltip(class="type">void) { class=class="str">"cmt">//--- 如果工具提示已经100%隐藏 if(m_alpha<class="num">1) class="kw">return; class=class="str">"cmt">//--- 标题的边缘 class="type">int y_offset=class="num">15; class=class="str">"cmt">//--- 透明度步长 class="type">uchar fadeout_step=class="num">7; class=class="str">"cmt">//--- 工具提示的逐渐淡出 for(class="type">uchar a=m_alpha; a>=class="num">0; a-=fadeout_step) { class=class="str">"cmt">//--- 如果下一步就变成负值,停止循环 if(a-fadeout_step<class="num">0) { a=class="num">0; m_canvas.Erase(::ColorToARGB(clrNONE,class="num">0)); m_canvas.Update(); m_alpha=class="num">0; class="kw">break; }
「自绘工具提示的渲染与鼠标驱动」
在 MT5 的 CCanvas 自绘体系里,工具提示不是系统控件,而是一块带渐变背景和边框的位图。标题坐标固定从 (5,5) 起步,若 m_header 非空,则用 FW_BLACK 字重画标题,否则主体文字直接顶到 (5,5)。 标题存在时,主体区坐标被推到 x=15、y=25;没有标题则回到 x=5、y=5。这个 10 像素的纵向偏移是肉眼可读性的硬门槛,调小到 5 以下文字会黏成一团。 主体文字按 m_tooltip_lines 数组逐行 TextOut,每画一行 y 累加 y_offset。FontSet 在这里切到 FW_THIN,和标题的 FW_BLACK 形成粗细对比,视觉层级一下就出来了。 鼠标移动事件(CHARTEVENT_MOUSE_MOVE)是显隐开关:元件隐藏、表单按钮禁用、或表单被锁,都会直接 return 或触发 FadeOutTooltip()。只有 m_element.MouseFocus() 为真才继续显示——意味着 tooltip 跟随的是具体子元件焦点,不是整窗悬停。
class=class="str">"cmt">//--- 标题坐标 class="type">int x =class="num">5; class="type">int y =class="num">5; class=class="str">"cmt">//--- 画出渐变和边框 VerticalGradient(a); Border(a); class=class="str">"cmt">//--- 画出标题 (如果指定) if(m_header!="") { class=class="str">"cmt">//--- 设置字体参数 m_canvas.FontSet(FONT,-class="num">80,FW_BLACK); class=class="str">"cmt">//--- 画出标题文字 m_canvas.TextOut(x,y,m_header,::ColorToARGB(m_header_color,a),TA_LEFT|TA_TOP); } class=class="str">"cmt">//--- 工具提示中主体文字的坐标 (考虑到标题存在与否) x=(m_header!="")? class="num">15 : class="num">5; y=(m_header!="")? class="num">25 : class="num">5; class=class="str">"cmt">//--- 设置字体参数 m_canvas.FontSet(FONT,-class="num">80,FW_THIN); class=class="str">"cmt">//--- 画出工具提示主体文字 class="type">int lines_total=::ArraySize(m_tooltip_lines); for(class="type">int i=class="num">0; i<lines_total; i++) { m_canvas.TextOut(x,y,m_tooltip_lines[i],::ColorToARGB(m_text_color,a),TA_LEFT|TA_TOP); y=y+y_offset; } class=class="str">"cmt">//--- 更新画布 m_canvas.Update(); } } class CWindow : class="kw">public CElement { class="kw">public: class=class="str">"cmt">//--- 检查工具提示显示模式 class="type">bool TooltipBmpState(class="type">void) const { class="kw">return(m_button_tooltip.State()); } }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 图表事件处理函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTooltip::OnEvent(const class="type">int id,const class="type">long &lparam,const class="type">class="kw">double &dparam,const class="type">class="kw">string &sparam) { class=class="str">"cmt">//--- 处理鼠标光标移动事件 if(id==CHARTEVENT_MOUSE_MOVE) { class=class="str">"cmt">//--- 如果元件是隐藏的就退出 if(!CElement::IsVisible()) class="kw">return; class=class="str">"cmt">//--- 如果表单上的工具提示按钮被禁用,就退出 if(!m_wnd.TooltipBmpState()) class="kw">return; class=class="str">"cmt">//--- 如果表单被屏蔽 if(m_wnd.IsLocked()) { class=class="str">"cmt">//--- 隐藏工具提示 FadeOutTooltip(); class="kw">return; } class=class="str">"cmt">//--- 如果元件上有焦点 if(m_element.MouseFocus()) class=class="str">"cmt">//--- 显示工具提示
class=class="str">"cmt">//--- 标题坐标 class="type">int x =class="num">5; class="type">int y =class="num">5; class=class="str">"cmt">//--- 画出渐变和边框 VerticalGradient(a); Border(a); class=class="str">"cmt">//--- 画出标题 (如果指定) if(m_header!="") { class=class="str">"cmt">//--- 设置字体参数 m_canvas.FontSet(FONT,-class="num">80,FW_BLACK); class=class="str">"cmt">//--- 画出标题文字 m_canvas.TextOut(x,y,m_header,::ColorToARGB(m_header_color,a),TA_LEFT|TA_TOP); } class=class="str">"cmt">//--- 工具提示中主体文字的坐标 (考虑到标题存在与否) x=(m_header!="")? class="num">15 : class="num">5; y=(m_header!="")? class="num">25 : class="num">5; class=class="str">"cmt">//--- 设置字体参数 m_canvas.FontSet(FONT,-class="num">80,FW_THIN); class=class="str">"cmt">//--- 画出工具提示主体文字 class="type">int lines_total=::ArraySize(m_tooltip_lines); for(class="type">int i=class="num">0; i<lines_total; i++) { m_canvas.TextOut(x,y,m_tooltip_lines[i],::ColorToARGB(m_text_color,a),TA_LEFT|TA_TOP); y=y+y_offset; } class=class="str">"cmt">//--- 更新画布 m_canvas.Update(); } } class CWindow : class="kw">public CElement { class="kw">public: class=class="str">"cmt">//--- 检查工具提示显示模式 class="type">bool TooltipBmpState(class="type">void) const { class="kw">return(m_button_tooltip.State()); } }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 图表事件处理函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CTooltip::OnEvent(const class="type">int id,const class="type">long &lparam,const class="type">class="kw">double &dparam,const class="type">class="kw">string &sparam) { class=class="str">"cmt">//--- 处理鼠标光标移动事件 if(id==CHARTEVENT_MOUSE_MOVE) { class=class="str">"cmt">//--- 如果元件是隐藏的就退出 if(!CElement::IsVisible()) class="kw">return; class=class="str">"cmt">//--- 如果表单上的工具提示按钮被禁用,就退出 if(!m_wnd.TooltipBmpState()) class="kw">return; class=class="str">"cmt">//--- 如果表单被屏蔽 if(m_wnd.IsLocked()) { class=class="str">"cmt">//--- 隐藏工具提示 FadeOutTooltip(); class="kw">return; } class=class="str">"cmt">//--- 如果元件上有焦点 if(m_element.MouseFocus()) class=class="str">"cmt">//--- 显示工具提示
◍ 焦点丢失时让提示淡出
在 MT5 自定义指标或脚本里做悬浮提示,不能只管显示不管回收。上面这段逻辑判断当前图表窗口是否持有输入焦点:有焦点就调用 ShowTooltip() 把信息亮出来,没焦点则走 FadeOutTooltip() 做渐隐退出,最后直接 return 结束本次事件处理。 实际跑起来你会看到,当鼠标移出图表子窗口或切到别的品种时,原来钉在 K 线上的注释框会在数帧内透明度递减消失,而不是硬切。这个细节能避免多图表同时开时提示层互相叠压,尤其在 4K 屏挂 6~8 个窗口时体验差异明显。 外汇与贵金属品种波动快、跳空频繁,这类纯界面逻辑虽不影响成交,但乱闪的提示可能干扰你对临场 price action 的阅读,建议先在策略测试器外的实盘模拟环境验证焦点切换行为。
ShowTooltip(); class=class="str">"cmt">//--- 如果没有焦点 else class=class="str">"cmt">//--- 隐藏工具提示 FadeOutTooltip(); class=class="str">"cmt">//--- class="kw">return; } }
给五个按钮挂上悬浮提示
界面跑起来后,测试表单上会多出 5 个按钮。想让每个按钮 hover 时弹出说明,就得声明 5 个 CTooltip 实例,并各写一个创建方法。下面只贴第 5 个的实现,其余四个结构一致,只是绑定的指针和文字不同。 工具提示的创建调用必须放在图形界面构建方法的末尾。这样它们会排进库内元件数组的尾巴,渲染层级最高,不会被图表其他对象挡住。若要在窗口标题栏显示那个小问号按钮来开关提示,创建时调一次 CWindow::UseTooltipsButton() 即可。 实际挂上后,鼠标移到第 5 个图标按钮上,会看到宽 250 像素、高 80 像素的浮层,头部写“Icon Button 5”,下面三行英文说明。外汇与贵金属图表挂这类 EA 界面属高风险操作,误触可能下发真实订单,建议在策略测试器里先验证。 代码里 TOOLTIP5_LINES_TOTAL 写死为 3,意味着只循环加三行字符串;若你改了 text 数组想加第 4 行,不调这个宏就会漏掉。多窗口模式下,这类 tooltip 还需要库维护一个私有数组来跨窗口追踪,后续再展开。
class CProgram : class="kw">public CWndEvents { class="kw">private: CTooltip m_tooltip1; CTooltip m_tooltip2; CTooltip m_tooltip3; CTooltip m_tooltip4; CTooltip m_tooltip5; class=class="str">"cmt">//--- class="kw">private: class="type">bool CreateTooltip1(class="type">void); class="type">bool CreateTooltip2(class="type">void); class="type">bool CreateTooltip3(class="type">void); class="type">bool CreateTooltip4(class="type">void); class="type">bool CreateTooltip5(class="type">void); }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 创建工具提示 class="num">5 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CProgram::CreateTooltip5(class="type">void) { class="macro">#define TOOLTIP5_LINES_TOTAL class="num">3 class=class="str">"cmt">//--- 保存窗口指针 m_tooltip5.WindowPointer(m_window1); class=class="str">"cmt">//--- 保存元件指针 m_tooltip5.ElementPointer(m_icon_button5); class=class="str">"cmt">//--- 工具提示文字的数组 class="type">class="kw">string text[]= { "Control \"Icon button\" (class="num">5).", "This is the second line of the tooltip.", "This is the third line of the tooltip." }; class=class="str">"cmt">//--- 在创建之前设置属性 m_tooltip5.Header("Icon Button class="num">5"); m_tooltip5.XSize(class="num">250); m_tooltip5.YSize(class="num">80); class=class="str">"cmt">//--- Добавим текст построчно for(class="type">int i=class="num">0;i<TOOLTIP5_LINES_TOTAL; i++) m_tooltip5.AddString(text[i]); class=class="str">"cmt">//--- 创建控件 if(!m_tooltip5.CreateTooltip(m_chart_id,m_subwin)) class="kw">return(false); class=class="str">"cmt">//--- 把对象加到通用对象数组中 CWndContainer::AddToElementsArray(class="num">0,m_tooltip5); class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 创建交易面板 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CProgram::CreateTradePanel(class="type">void) { class=class="str">"cmt">//--- 为控件创建表单1 class=class="str">"cmt">//--- 创建控件: class=class="str">"cmt">// 主菜单 class=class="str">"cmt">//--- 上下文菜单 class=class="str">"cmt">//--- 创建状态栏 class=class="str">"cmt">//--- 图标按钮 class=class="str">"cmt">//--- 工具提示 if(!CreateTooltip1()) class="kw">return(false); if(!CreateTooltip2()) class="kw">return(false); if(!CreateTooltip3()) class="kw">return(false); if(!CreateTooltip4()) class="kw">return(false); if(!CreateTooltip5()) class="kw">return(false); class=class="str">"cmt">//--- 重绘图表 m_chart.Redraw(); class="kw">return(true); }
「给指标面板挂上第一个可拖拽窗口」
在 MT5 自定义指标里做 GUI,第一步往往是把控件容器接进窗口管理数组。上面这段 CProgram::CreateWindow1 做的就是往 CWndContainer 注册 m_window1 指针,并给定初始坐标 x=1、y=20,避开图表左上角被系统占用的一小块区域。 窗口尺寸定在 251×200 像素,Movable(true) 允许交易者拖动,UseTooltipsButton() 那行(原文高亮)会给标题栏加一个提示按钮,鼠标悬停可看说明——做多表单时这个功能很实用,免得参数含义靠猜。 标题栏配色用了 CornflowerBlue,悬停态转成自定义的 C'150,190,240' 浅蓝。CreateWindow 失败直接返回 false,调用方应当检查返回值,否则面板无声消失时你只能在日志里翻原因。外汇与贵金属图表加载此类 EA/指标属高风险操作,建议先在 demo 账户验证窗口行为。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 创建控件表单1 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CProgram::CreateWindow1(const class="type">class="kw">string caption_text) { class=class="str">"cmt">//--- 在窗口数组中加入窗口指针 CWndContainer::AddWindow(m_window1); class=class="str">"cmt">//--- 坐标 class="type">int x=class="num">1; class="type">int y=class="num">20; class=class="str">"cmt">//--- 属性 m_window1.Movable(true); m_window1.XSize(class="num">251); m_window1.YSize(class="num">200); m_window1.UseTooltipsButton(); m_window1.CaptionBgColor(clrCornflowerBlue); m_window1.CaptionBgColorHover(C&class="macro">#x27;class="num">150,class="num">190,class="num">240&class="macro">#x27;); class=class="str">"cmt">//--- 创建表单 if(!m_window1.CreateWindow(m_chart_id,m_subwin,caption_text,x,y)) class="kw">return(false); class=class="str">"cmt">//--- class="kw">return(true); }
◍ 给容器类塞一个工具提示私有数组
在 CWndContainer 里扩展 WindowElements 结构,加一个 CTooltip* 类型的私有动态数组 m_tooltips[],专门收工具提示指针。配套两个方法:TooltipsTotal() 按窗口索引返回该数组长度,AddTooltipElements() 负责把新加的元件若是工具提示就存进私有数组。 AddTooltipElements() 只在 AddToElementsArray() 公有方法里被调用,也就是说每次往自定义类项库塞元件都会顺带过滤一遍。代码里用 ClassName()!="CTooltip" 做类型判断,非工具提示直接返回 false,不污染数组。 TooltipsTotal() 有越界保护:window_index 大于等于 m_wnd 总尺寸时打印 PREVENTING_OUT_OF_RANGE 并返回 WRONG_VALUE,正常情况直接返回 m_wnd[window_index].m_tooltips 的 ArraySize。开 MT5 把这段贴进你的容器类,编译后调用 TooltipsTotal(0) 就能验证主图窗口挂了几个提示对象。外汇与贵金属 GUI 开发属高风险定制,参数错误可能让面板无响应。
class CWndContainer { class="kw">protected: class=class="str">"cmt">//--- 元件数组结构 class="kw">struct WindowElements { class=class="str">"cmt">//--- 工具提示 CTooltip *m_tooltips[]; }; class=class="str">"cmt">//--- 每个窗口的元件数组的数组 WindowElements m_wnd[]; class=class="str">"cmt">//--- class="kw">public: class=class="str">"cmt">//--- 工具提示的数量 class="type">int TooltipsTotal(const class="type">int window_index); class=class="str">"cmt">//--- class="kw">private: class=class="str">"cmt">//--- 保存库中元件的工具提示指针 class="type">bool AddTooltipElements(const class="type">int window_index,CElement &object); }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 根据指定窗口索引返回工具提示数量 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int CWndContainer::TooltipsTotal(const class="type">int window_index) { if(window_index>=::ArraySize(m_wnd)) { ::Print(PREVENTING_OUT_OF_RANGE); class="kw">return(WRONG_VALUE); } class=class="str">"cmt">//--- class="kw">return(::ArraySize(m_wnd[window_index].m_tooltips)); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 在私有数组中保存工具提示的指针 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CWndContainer::AddTooltipElements(const class="type">int window_index,CElement &object) { class=class="str">"cmt">//--- 如果不是工具提示,退出 if(object.ClassName()!="CTooltip") class="kw">return(false); class=class="str">"cmt">//--- 取得工具提示指针 CTooltip *t=::GetPointer(object); class=class="str">"cmt">//--- 把指针加到私有数组中 AddToRefArray(t,m_wnd[window_index].m_tooltips); class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 把指针加到元件数组中 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CWndContainer::AddToElementsArray(const class="type">int window_index,CElement &object) { class=class="str">"cmt">//--- 如果库中没有包含控件表单 class=class="str">"cmt">//--- 如果需求是为了不存在的表单 class=class="str">"cmt">//--- 添加到通用元件数组中 class=class="str">"cmt">//--- 把元件对象加到通用对象数组中 class=class="str">"cmt">//--- 保存所有表单中最后一个元件的id class=class="str">"cmt">//--- 元件id计数器加1 class=class="str">"cmt">//--- 在库中保存上下文菜单对象的指针 class=class="str">"cmt">//--- 在库中保存主菜单对象的指针 class=class="str">"cmt">//--- 在库中保存分割按钮对象的指针 class=class="str">"cmt">//--- 在库中保存工具提示对象的指针 if(AddTooltipElements(window_index,object)) class="kw">return; }
把这条线请下神坛
这一节原本只是交代后续章节与附件下载,但落到实盘界面开发上,重点就一句:状态栏和工具提示元件已经跑通,下一章才碰多窗口与左键优先级。附件里 mql5 包 170.73 KB、mql4 包 170.75 KB,解压后直接丢进 MT5 的 MQL5/Include 就能编译验证。 俄文原帖下有人反馈生成不了面板,作者回链到 GUI X 第 13 版才修好,说明早期库对中文路径或编译器版本敏感。你本地若报错,先核对 include 引用路径,别急着改逻辑。 外汇与贵金属 GUI 自动化本就高风险,界面卡顿可能让你漏掉滑点窗口;把这套元件当辅助,别当成下单依据。