研究CCanvas类如何绘制透明的图形对象·进阶篇
(2/3)· 屏幕只有二维像素,却要靠ARGB骗出玻璃杯的半透明错觉,这篇拆开讲
很多人以为在MT5里画个半透明框只是调低颜色亮度,结果图层一叠就糊成一片。屏幕本质是二维像素矩阵,没有真实深度,透明全靠Alpha通道和混合算出来。不懂这套,你写的面板永远像贴纸而不是悬浮层。
◍ ARGB 四字节怎么塞进透明度
MQL5 里 ARGB 用 uint 四字节表达,顺序固定为 alpha、红、绿、蓝。它本质是在 RGB 三通道外硬塞一个 alpha 字节,专门管前景和背景的叠加关系,而不是改色相。 alpha 取值 0–255:0 表示前景完全不动背景像素,255 表示背景被前景彻底盖掉。换算成百分比透明度时,alpha 越小反而越透,这点容易看反——比如 alpha=25 时透明度约 90%,alpha=128 时约 50%。 实际写指标或面板时,别手算字节,直接调 ColorToARGB(颜色, alpha) 把普通颜色转成带透明的 uint。开 MT5 敲一行测试:Print(ColorToARGB(clrRed, 128)); 能在日志看到红通道半透明对应的数值,验证叠加逻辑再接到 ObjCreate 一类的绘图对象上。
背景层与前景层的对象叠色逻辑
MT5 图表窗口实际由 4 个图层构成,两端分别是背景层和前景层。右键图表 → Properties... → Common 标签页里可切换对象绘制在背景还是前景;同一图层内,先创建的对象沉底,后创建的盖在上层,创建时间直接决定 Z 轴顺序。 绝大多数图形对象(垂直线、趋势线、斐波那契系列、各类箭头与文本标签等共 40 余种)与底层重叠时「不重绘」,唯独矩形、三角形、椭圆形这三类在填充状态下会触发重叠区重绘,不填充则同样不重绘。 重绘走的是按位 OR(Bitwise OR)算法。脚本 xor.mq5 设白底 0xFFFFFF,叠放蓝 0x0000FF 与红 0xFF0000 填充矩形:蓝+蓝再 OR 白底得 0x000000(透明,透出背景);蓝+红再 OR 白底得 0x00FF00(绿)。两个重叠区最终色变可现场在 MT5 跑脚本验证。 开启「图表的前景」参数后,前景与背景两绘制层合并为 K 线与网格线之下的公共层。对比图 7 与图 9 可知,合并前后重叠区的 Bitwise OR 重绘结果一致,图层归属变化不影响叠色输出。外汇与贵金属图表叠加对象时波动剧烈,叠加验证请先在模拟盘走一遍。
「半透明红在白底上到底变成什么」
屏幕上的透明只是算法算出来的视觉差。想在白底图表上画一支 alpha=128 的红色(ARGB 里是 0x80FF0000),终端并不是真的「透」,而是按通道把前景色和背景色掺在一起。 归一化公式里,result = background*(1-alpha) + foreground*alpha,任一通道算出来超 255 就截断回 255。把白色背景(255,255,255)和 alpha 归一化后 0.5 的纯红(255,0,0)代进去:R = 255*0.5+255*0.5 = 255,G = 255*0.5+0*0.5 = 127,B 同 G = 127,最终屏幕上看到的是 (255,127,127) 的浅红,不是你代码里写的那个红。 建画布时 ENUM_COLOR_FORMAT 给了三条路:COLOR_FORMAT_XRGB_NOALPHA 直接扔掉 alpha;COLOR_FORMAT_ARGB_NORMALIZE 由终端按上面公式算好叠加,图形更干净但吃算力;COLOR_FORMAT_ARGB_RAW 不帮你算 RGB 重叠,速度快,颜色得自己算准。做高频重绘的 HUD 图层,RAW 更稳,做一次性标注图用 NORMALIZE 省心。 外汇和贵金属图表叠加半透明层只是显示辅助,不改报价本身,实盘叠加任何视觉层都不降低品种的高风险属性。
◍ 三种色彩模式下的透明度渐变实验
在 MT5 图表顶层铺三块互不重叠的水平画布,分别用 COLOR_FORMAT_XRGB_NOALPHA、COLOR_FORMAT_ARGB_RAW、COLOR_FORMAT_ARGB_NORMALIZE 处理颜色,再把 alpha 从 255 逐步降到 0,就能直观看出三种模式对透明的解释差异。 先拿标准函数抓图表宽高,算出画布尺寸与坐标辅助变量,随后在 OnStart 里把 void 改成 int,第一块画布用 XRGB_NOALPHA 画填充矩形、模式名文本和实心圆。该模式直接忽略 alpha 通道,即便用带透明的 ARGB 色去 Erase 整块画布,底层图像也会被完全覆盖,不存在混色。 另外两块画布按 RAW 与 NORMALIZE 模式如法炮制,最后套一个循环统一改 alpha 并刷新屏幕。脚本收尾必须用 Destroy() 删掉 CreateBitmapLabel 建的图形资源,否则图表对象会残留。 白底和黑底各跑一次 Illusion.mq5,RAW 与 NORMALIZE 的边界区别最明显:前者不按背景做亮度归一,后者会随底色重算显示强度。外汇与贵金属图表叠加此类透明层时,视觉误差可能误导价位判断,属高风险操作环境,参数请自行在策略测试器外验证。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Illusion.mq5 | class=class="str">"cmt">//| Copyright © class="num">2015, Vladimir Karputov | class=class="str">"cmt">//| http://wmua.ru/slesar/ | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright © class="num">2015, Vladimir Karputov" class="macro">#class="kw">property link "http:class=class="str">"cmt">//wmua.ru/slesar/" class="macro">#class="kw">property version "class="num">1.0" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 脚本程序start函数 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { class=class="str">"cmt">//--- } class="macro">#class="kw">property version "class="num">1.0" class="macro">#class="kw">property description "The illusion of transparency" class=class="str">"cmt">//--- 加载脚本时显示输入参数窗口 class="macro">#class="kw">property script_show_inputs class="macro">#include <Canvas\Canvas.mqh> class="macro">#include <Canvas\Canvas.mqh> class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| inputs | class=class="str">"cmt">//+------------------------------------------------------------------+ input class="type">color colr=clrRed; input class="type">color clr_Circle=clrBlue; class=class="str">"cmt">//--- 图表高度和宽度变量。 class="type">int ChartWidth=-class="num">1; class="type">int ChartHeight=-class="num">1; class=class="str">"cmt">//--- class="type">uchar alpha=class="num">0; class=class="str">"cmt">//控制色彩透明度的alpha通道值 class="type">int can_width,can_height; class=class="str">"cmt">//画布的高度和宽度变量。 class="type">int can_x1,can_y1,can_x2,can_y2,can_y3,can_x3; class=class="str">"cmt">//坐标