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