研究CCanvas类如何绘制透明的图形对象·综合运用
(3/3)· 前面铺垫了颜色与图层原理,这一篇把透明图形真正画进终端并处理好重绘与混色
◍ 抓取图表像素尺寸来切分画布
想在 MT5 图表上自绘多宫格画布,第一步得拿到窗口的真实像素宽高,而不是猜。下面两个函数分别用 ChartGetInteger 读 CHART_WIDTH_IN_PIXELS 和 CHART_HEIGHT_IN_PIXELS,失败就打错误码,成功把 long 转成 int 返回。 ChartHeightInPixelsGet 比宽度函数多一个 sub_window 参数,默认 0 指主图窗口;若你想在副图指标区绘图,传对应子窗口序号即可。 在 OnStart 里调用后,代码把 ChartHeight 减掉 50 像素(给终端工具栏留白),再把宽三等分:can_width=ChartWidth/3,三个画布左上角 x 分别为 0、can_width、can_width*2,y 都从 0 起。开 MT5 新建脚本粘这段,跑完在日志看返回值,就能确认你的图表被切成三竖条。 别把终端框架高度算进去 减 50 只是经验值,不同 DPI 下边框占用可能偏差;真要精准布局,建议先 Print 原始 ChartHeight 再动态扣减。
class="type">int ChartWidthInPixels(const class="type">long chart_ID=class="num">0) { class="type">long result=-class="num">1; ResetLastError(); if(!ChartGetInteger(chart_ID,CHART_WIDTH_IN_PIXELS,class="num">0,result)) { Print(__FUNCTION__+", Error Code = ",GetLastError()); } class="kw">return((class="type">int)result); } class="type">int ChartHeightInPixelsGet(const class="type">long chart_ID=class="num">0,const class="type">int sub_window=class="num">0) { class="type">long result=-class="num">1; ResetLastError(); if(!ChartGetInteger(chart_ID,CHART_HEIGHT_IN_PIXELS,sub_window,result)) { Print(__FUNCTION__+", Error Code = ",GetLastError()); } class="kw">return((class="type">int)result); } class="type">void OnStart() { ChartWidth=ChartWidthInPixels(); ChartHeight=ChartHeightInPixelsGet()-class="num">50; can_width=ChartWidth/class="num">3; can_height=ChartHeight; can_x1=class="num">0; can_y1=class="num">0; can_x2=can_width; can_y2=class="num">0; can_x3=can_width*class="num">2; can_y3=class="num">0; }
三种画布色彩格式的差异与落地写法
在 MT5 的 Canvas 类里,COLOR_FORMAT_XRGB_NOALPHA、COLOR_FORMAT_ARGB_RAW、COLOR_FORMAT_ARGB_NORMALIZE 是三种常见像素格式。它们都通过 CreateBitmapLabel 创建位图标签,但底层 alpha 通道处理不同,肉眼看同一段绘制代码可能出现透明度或混合效果的偏差。 以 XRGB_NOALPHA 为例,创建时宽高传 can_width-1 和 can_height,若失败直接 Print(GetLastError()) 并 return(-1)。随后 Erase 用 ColorToARGB(colr,alpha) 清底,TextOut 在中心写蓝字,FillCircle 在垂直偏移 50 像素处画半径 25 的圆,最后 Update 刷新。 ARGB_RAW 与 XARGB_NORMALIZE 的调用序列完全一致,仅格式宏不同。实盘加载后你可能会发现:NORMALIZE 在重叠元素时倾向做 alpha 归一,RAW 则更贴近原始通道值。外汇与贵金属图表叠加自绘层时属高风险操作,建议先在策略测试器里验证显示逻辑。 下面这段是可直接贴进 OnDraw 验证的原文核心:
if(!canvas_XRGB_NOALPHA.CreateBitmapLabel("canvas_XRGB_NOALPHA",can_x1,can_y1,can_width-class="num">1,can_height,COLOR_FORMAT_XRGB_NOALPHA)) { Print("Error creating canvas: ",GetLastError()); class="kw">return(-class="num">1); } canvas_XRGB_NOALPHA.Erase(ColorToARGB(colr,alpha)); canvas_XRGB_NOALPHA.TextOut((can_width)/class="num">2,can_height/class="num">2,"canvas_XRGB_NOALPHA",ColorToARGB(clrBlue,class="num">255),TA_CENTER|TA_VCENTER); canvas_XRGB_NOALPHA.FillCircle((can_width)/class="num">2,can_height/class="num">2+class="num">50,class="num">25,ColorToARGB(clr_Circle,class="num">255)); canvas_XRGB_NOALPHA.Update(); class="kw">return(class="num">0); if(!canvas_ARGB_RAW.CreateBitmapLabel("canvas_ARGB_RAW",can_x2,can_y2,can_width-class="num">1,can_height,COLOR_FORMAT_ARGB_RAW)) { Print("Error creating canvas: ",GetLastError()); class="kw">return(-class="num">1); } canvas_ARGB_RAW.Erase(ColorToARGB(colr,alpha)); canvas_ARGB_RAW.TextOut((can_width)/class="num">2,can_height/class="num">2,"canvas_ARGB_RAW",ColorToARGB(clrBlue,class="num">255),TA_CENTER|TA_VCENTER); canvas_ARGB_RAW.FillCircle((can_width)/class="num">2,can_height/class="num">2+class="num">50,class="num">25,ColorToARGB(clr_Circle,class="num">255)); canvas_ARGB_RAW.Update(); if(!canvas_XARGB_NORMALIZE.CreateBitmapLabel("canvas_XARGB_NORMALIZE",can_x3,can_y3,can_width-class="num">1,can_height,COLOR_FORMAT_ARGB_NORMALIZE)) { Print("Error creating canvas: ",GetLastError()); class="kw">return(-class="num">1); } canvas_XARGB_NORMALIZE.Erase(ColorToARGB(colr,alpha)); canvas_XARGB_NORMALIZE.TextOut((can_width)/class="num">2,can_height/class="num">2,"canvas_XARGB_NORMALIZE",ColorToARGB(clrBlue,class="num">255),TA_CENTER|TA_VCENTER); canvas_XARGB_NORMALIZE.FillCircle((can_width)/class="num">2,can_height/class="num">2+class="num">50,class="num">25,ColorToARGB(clr_Circle,class="num">255)); canvas_XARGB_NORMALIZE.Update(); class="kw">return(class="num">0);
「三类画布的透明度渐变实测」
在 MT5 的 Canvas 绘图里,XRGB_NOALPHA、ARGB_RAW、XARGB_NORMALIZE 三种画布对透明度的处理并不一致,直接循环降透明度是最快的肉眼验证法。 下面这段把 transparent 从 255 递减到 0,每步间隔 50 毫秒调用 TransparentLevelSet 并 Update,你能直接在副图看到三层叠加图形的淡出节奏差异。外汇与贵金属图表叠加自绘层时,这种差异可能导致信号遮挡误判,属高风险操作需自行回测。 循环结束后再把三块画布显式设为 0 并 Update,留 6 秒观察终态,最后 Destroy 释放资源。跑完这套,你该能确认:ARGB_RAW 的透明混合最贴近像素原始值,XARGB_NORMALIZE 会自动按背景归一化,别凭直觉选画布类型。
class=class="str">"cmt">//--- 透明度从255到0 class="type">uchar transparent; for(transparent=class="num">255;transparent>class="num">0;transparent--) { canvas_XRGB_NOALPHA.TransparentLevelSet(transparent); canvas_XRGB_NOALPHA.Update(); canvas_ARGB_RAW.TransparentLevelSet(transparent); canvas_ARGB_RAW.Update(); canvas_XARGB_NORMALIZE.TransparentLevelSet(transparent); canvas_XARGB_NORMALIZE.Update(); Sleep(class="num">50); } canvas_XRGB_NOALPHA.TransparentLevelSet(transparent); canvas_XRGB_NOALPHA.Update(); canvas_ARGB_RAW.TransparentLevelSet(transparent); canvas_ARGB_RAW.Update(); canvas_XARGB_NORMALIZE.TransparentLevelSet(transparent); canvas_XARGB_NORMALIZE.Update(); Sleep(class="num">6000); class="kw">return(class="num">0); } class=class="str">"cmt">//--- 完成 canvas_XRGB_NOALPHA.Destroy(); canvas_ARGB_RAW.Destroy(); canvas_XARGB_NORMALIZE.Destroy(); class="kw">return(class="num">0); }
◍ 一点提醒
把 ARGB 里的 Alpha 通道玩顺手之后,CCanvas 画出来的半透明对象确实比生硬实色更有层次,但别以为这就是真三维——屏幕只有二维像素,所谓透明只是混合运算造出的视觉错觉。 评论区里那串玻璃透光推算挺实在:两块减光 40% 和 50% 的镜片叠一起,透过的光是原来强度的 30%,公式就是 New_alpha = a1 + a2 - a1*a2,和从属事件概率求和一个道理,拿到 MT5 里算颜色叠加时可直接套。 外汇与贵金属图表叠加自绘图形本就伴随报价跳变的高风险,拿这类视觉把戏辅助判断可以,但别把它当价格结论。