研究 CCanvas 类。抗锯齿和阴影(基础篇)
📘

研究 CCanvas 类。抗锯齿和阴影(基础篇)

第 1/3 篇

用 CCanvas 画平滑阴影

MQL5 标准库里的 CCanvas 类能在离线图(resource)上做像素级绘制,比直接调 Windows GDI 省事。想让画线或图形边缘不发毛刺,关键在抗锯齿开关;想让指标面板有立体感,则要靠阴影偏移。 CCanvas 默认不开启抗锯齿,需显式调用 AntiAliasing(true)。阴影一般做法是先把同形状用半透明黑画在右下偏移 2~3 像素处,再画主体。下面这段演示最小可用骨架。 外汇与贵金属行情跳动快、点差突变频繁,任何基于历史图形的叠加层都只是辅助视角,不预示后续方向,实盘请自担高风险。

MQL5 / C++
CCanvas canvas;
canvas.CreateBitmapLabel("Panel",class="num">0,class="num">0,class="num">200,class="num">100,COLOR_FORMAT_ARGB);
canvas.AntiAliasing(true);
canvas.FillRectangle(class="num">10,class="num">10,class="num">190,class="num">90,ColorToARGB(clrWhite,class="num">255));
canvas.Shadow(class="num">2,class="num">2,ColorToARGB(clrBlack,class="num">80));
canvas.FillRectangle(class="num">10,class="num">10,class="num">190,class="num">90,ColorToARGB(clrDodgerBlue,class="num">255));
canvas.Update();

「这篇图形引擎拆解的脉络」

MQL5 自定义图形绘制并不是简单调个线就完事,底层涉及坐标映射、画布缓冲与像素级处理。 本篇后续会依次铺开:先讲坐标与画布基准,再进入抗锯齿;随后是对象阴影模块,其中正态分布采样与资源管理是阴影质感的关键;高斯模糊示例与封装类放在后面实证。 外汇与贵金属图表叠加这类自绘层时,需注意终端渲染开销偏高,复杂阴影在低频帧下可能拖慢盯盘响应。

◍ 用 CCanvas 把指标画出动态感

MQL5 标准库里的 CCanvas 类,能在独立窗口里直接操作像素缓冲,绕开普通指标线那种静态重绘的限制。它最实用的两个点:一是可以接抗锯齿算法,让图形边缘不再锯齿状,观感更接近专业图表软件;二是支持花键(spline)样式画线,比普通折线更能表达平滑过渡。 如果你在做一个需要“示波器式”实时刷新的副图指标,比如频率响应或自定义波动率带,用 CCanvas 在独立窗口逐帧绘制,是标准做法。外汇和贵金属品种波动快、跳空多,这类动态绘制对 CPU 占用要实测,EA 或指标在实盘前务必在 MT5 策略测试器里跑一遍压力验证。 绘图层解放后,个人开发者的发挥空间明显变大——从纯分析到带交互的面板都有可能。但它只是渲染工具,信号逻辑本身仍需你自己在 OnCalculate 里写清楚。

画布坐标与抗锯齿的像素规则

MT5 的画布坐标系内嵌在图表里,尺寸按像素计,左上角原点是 (0,0)。普通绘制接口坐标和颜色都用 int,但抗锯齿系列方法类型混杂:PixelSetAA 坐标是 double,CircleAA 坐标是 int、半径却是 double,其余 LineAA、PolylineAA 等全是 int。 下面这张类型对照直接决定你传参时会不会编译报错: PixelSetAA → double LineAA / PolylineAA / PolygonAA / TriangleAA → int CircleAA → 坐标 int、尺寸 double 脚本 PixelSetAA.mq5 画了两列各 11 个点做对照:左列 X 每点 +0.1、Y +3.0;右列 X +0.1、Y +3.1。放大数倍后能看清差异——左列只有一个坐标是小数,点会用两种饱和度的像素着色;右列 XY 都是小数,每个点占三个不同饱和度像素,靠这种过渡实现视觉平滑。 外汇和贵金属图表叠加自绘层时,这种亚像素着色会吃掉额外 CPU,点密时要留意图表卡顿风险。

「虚拟像素怎么骗过眼睛」

CCanvas 里所有带 AA 后缀的画法,从 LineAA 到 CircleAA,最终都落到一个叫 PixelSetAA 的基础方法上。它的 X、Y 参数是 double 类型,意味着坐标可以落在物理像素的缝隙之间,而不是死贴在某个整数格点上。 一个虚拟像素经常带着分数坐标,最多同时压住四个物理像素。抗锯齿的本质就是用这一个虚拟点的颜色,按不同权重给这四个真实像素上色,让肉眼看到柔边和缓变的色块,而不是硬邦邦的锯齿。 算法先 MathRound 把传入坐标舍入成整数 ix、iy,再算 dx=x-ix、dy=y-iy。若 dx 和 dy 都等于零,说明点正好落在像素中心,方法直接退出不浪费算力;只要有偏差,就进入数组准备阶段。 下面这段是 PixelSetAA 的静态数组声明和初步计算核心,配合一段验证 MathRound 行为的脚本输出,能直接拷进 MT5 看舍入结果:MathRound(3.5) 向上进到 4,MathRound(3.2) 回到 3,含 .5 时统一进位。外汇与贵金属图表自定义绘图属高风险辅助,参数错了只影响视觉不影响报价。 rr[4]、xx[4]、yy[4] 三个静态数组分别存覆盖权重和四个物理像素坐标,后续按 dx、dy 算出的权重把颜色摊进去,模糊就完成了。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 绘制抗锯齿像素                                                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CCanvas::PixelSetAA(class="kw">const class="type">class="kw">double x,class="kw">const class="type">class="kw">double y,class="kw">const class="type">uint clr)
  {
  class="kw">static class="type">class="kw">double rr[class="num">4];
  class="kw">static class="type">int    xx[class="num">4];
  class="kw">static class="type">int    yy[class="num">4];
class=class="str">"cmt">//--- 初步计算
  class="type">int    ix=(class="type">int)MathRound(x);
  class="type">int    iy=(class="type">int)MathRound(y);
  class="type">class="kw">double dx=x-ix;
  class="type">class="kw">double dy=y-iy;
  class="type">class="kw">double rrr=class="num">0;
  class="type">class="kw">double k;
  }

常见问题

开启抗锯齿后先填半透明黑再做模糊偏移,阴影边缘会按虚拟像素过渡,肉眼看不到台阶状像素。
画布用了虚拟像素映射,需按设备缩放比换算坐标,否则图形会整体偏移,调试时打印坐标差值即可定位。
小布可读取你的画布配置和坐标逻辑,提示抗锯齿开关状态并标出偏移异常,省去手动逐行查。
只重绘变化区域而非整图,配合双缓冲画布,动态感流畅且CPU占用明显下降。
虚拟像素是按缩放合成的抽象单位,用多个物理像素凑渐变,眼睛会把硬边当成平滑过渡。