在 MQL 应用程序中运用 CCanvas 类·进阶篇
在像素缓冲里直接画图形
MQL5 的绘图对象暴露了一组直接操作 m_pixels 数组的接口,绕开终端自带图形元素,适合做自定义指标层或离屏合成。下面这组方法覆盖了从字体、线型到基础图元的完整绘制链路。 FontGet 以引用方式取出当前字体名、尺寸、标志与旋转角;LineStyleGet / LineStyleSet 则读写线型常量(如 STYLE_SOLID、STYLE_DASH)。TextOut 把字符串写进像素数组,可带对齐参数 alignment,默认 0 即左上对齐。 PixelGet 与 PixelSet 按 x、y 坐标读改单点颜色,是后续所有图元的基础。LineVertical、LineHorizontal、Line 分别画竖线、横线、任意斜率线;Polyline 与 Polygon 接收 int 数组坐标批量连线或闭合填色。 Rectangle、Triangle、Circle、Ellipse 对应四种闭合图元,坐标均为像素整数。末尾的 PixelSetAA 与 LineAA 带抗锯齿,LineAA 的 style 默认 UINT_MAX 表示沿用对象当前线型——做平滑曲线时优先用这两个而不是普通 Line。 外汇与贵金属图表叠加自绘层波动剧烈,直接像素操作若每帧重绘全屏,CPU 占用可能明显抬升,建议在 OnCalculate 里做脏区判断再局部刷新。
class="type">void FontGet(class="type">class="kw">string &name,class="type">int &size,class="type">uint &flags,class="type">uint &angle); class=class="str">"cmt">// Get font properties class="type">uint LineStyleGet(class="type">void) class="kw">const; class=class="str">"cmt">// Return the specified line drawing style class="type">void LineStyleSet(class="kw">const class="type">uint style); class=class="str">"cmt">// Set the line drawing style class="type">void TextOut(class="type">int x,class="type">int y,class="type">class="kw">string text,class="kw">const class="type">uint clr,class="type">uint alignment=class="num">0); class=class="str">"cmt">// Display text to the m_pixels array class="type">uint PixelGet(class="kw">const class="type">int x,class="kw">const class="type">int y) class="kw">const; class=class="str">"cmt">// Return the pixel class="type">color value according to x and y coordinates class="type">void PixelSet(class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">uint clr); class=class="str">"cmt">// Change the pixel class="type">color value according to x and y coordinates class="type">void LineVertical(class="type">int x,class="type">int y1,class="type">int y2,class="kw">const class="type">uint clr); class=class="str">"cmt">// Draw a vertical line according to specified coordinates and class="type">color class="type">void LineHorizontal(class="type">int x1,class="type">int x2,class="type">int y,class="kw">const class="type">uint clr); class=class="str">"cmt">// Draw a horizontal line according to specified coordinates and class="type">color class="type">void Line(class="type">int x1,class="type">int y1,class="type">int x2,class="type">int y2,class="kw">const class="type">uint clr); class=class="str">"cmt">// Draw a freehand line according to specified coordinates and class="type">color class="type">void Polyline(class="type">int &x[],class="type">int &y[],class="kw">const class="type">uint clr); class=class="str">"cmt">// Draw a polyline according to specified coordinates and class="type">color class="type">void Polygon(class="type">int &x[],class="type">int &y[],class="kw">const class="type">uint clr); class=class="str">"cmt">// Draw a polygon according to specified coordinates and class="type">color class="type">void Rectangle(class="type">int x1,class="type">int y1,class="type">int x2,class="type">int y2,class="kw">const class="type">uint clr); class=class="str">"cmt">// Draw a rectangle according to specified coordinates and class="type">color class="type">void Triangle(class="type">int x1,class="type">int y1,class="type">int x2,class="type">int y2,class="type">int x3,class="type">int y3,class="kw">const class="type">uint clr); class=class="str">"cmt">// Draw a triangle according to specified coordinates and class="type">color class="type">void Circle(class="type">int x,class="type">int y,class="type">int r,class="kw">const class="type">uint clr); class=class="str">"cmt">// Draw a circle according to specified coordinates, radius and class="type">color class="type">void Ellipse(class="type">int x1,class="type">int y1,class="type">int x2,class="type">int y2,class="kw">const class="type">uint clr); class=class="str">"cmt">// Draw an ellipse according to specified coordinates and class="type">color class=class="str">"cmt">//--- Methods for drawing primitives with smoothing using antialiasing class="type">void 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="type">void LineAA(class="kw">const class="type">int x1,class="kw">const class="type">int y1,class="kw">const class="type">int x2,class="kw">const class="type">int y2,class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX);
◍ 抗锯齿图元绘制的双算法入口
在 MT5 自定义指标里画平滑图形,核心类给了两套抗锯齿方案:AA 后缀走经典超采样思路,Wu 后缀用吴小林(Wu's)误差扩散算法,两者函数签名几乎平行,只是 AA 组部分接收可修改的引用数组而 Wu 组全用 const 数组。 所有函数末尾都带 style=UINT_MAX 的默认参数,意味着不传线型时由内部按抗锯齿过滤器预设处理;颜色统一用 uint 打包的 ARGB,直接喂 clr 常量或自定义数值都行。 实际盯盘面板里,若你要在分时叠加区画多边形压力带,PolygonWu 比 PolygonAA 在 CPU 占用上倾向更轻——同样 6 顶点多边形,Wu 算法少一次全屏采样,回测脚本里帧耗时可能低 15%~20%。外汇与贵金属图表高频重绘时,这个差异在 4K 屏上更容易被察觉,相关品种波动剧烈、杠杆风险高,参数务必先在模拟环境验证。 下面这组声明就是可直接抄进 CTrade 或 Canvas 封装类的接口原型,注意 AA 版 Polyline 的 x[]、y[] 带 & 引用,调用前数组须已分配长度。
class="type">void PolylineAA(class="type">int &x[],class="type">int &y[],class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class="type">void PolygonAA(class="type">int &x[],class="type">int &y[],class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class="type">void TriangleAA(class="kw">const class="type">int x1,class="kw">const class="type">int y1,class="kw">const class="type">int x2,class="kw">const class="type">int y2,class="kw">const class="type">int x3,class="kw">const class="type">int y3,class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class="type">void CircleAA(class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">class="kw">double r,class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class="type">void EllipseAA(class="kw">const class="type">class="kw">double x1,class="kw">const class="type">class="kw">double y1,class="kw">const class="type">class="kw">double x2,class="kw">const class="type">class="kw">double y2,class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class=class="str">"cmt">//--- Methods for drawing primitives with smoothing using Wu&class="macro">#x27;s algorithm class="type">void LineWu(class="type">int x1,class="type">int y1,class="type">int x2,class="type">int y2,class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class="type">void PolylineWu(class="kw">const class="type">int &x[],class="kw">const class="type">int &y[],class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class="type">void PolygonWu(class="kw">const class="type">int &x[],class="kw">const class="type">int &y[],class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class="type">void TriangleWu(class="kw">const class="type">int x1,class="kw">const class="type">int y1,class="kw">const class="type">int x2,class="kw">const class="type">int y2,class="kw">const class="type">int x3,class="kw">const class="type">int y3,class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class="type">void CircleWu(class="kw">const class="type">int x,class="kw">const class="type">int y,class="kw">const class="type">class="kw">double r,class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class="type">void EllipseWu(class="kw">const class="type">int x1,class="kw">const class="type">int y1,class="kw">const class="type">int x2,class="kw">const class="type">int y2,class="kw">const class="type">uint clr,class="kw">const class="type">uint style=UINT_MAX); class=class="str">"cmt">//--- Methods for drawing primitives with preliminarily set antialiasing filter
「厚线绘制接口的参数门道」
在 MT5 自定义图形库里,一组以 LineThick 开头的函数专门负责带宽度和端样式的线段绘制,区别于系统原生 Thin 线。垂直、水平、任意角度线段分别由 LineThickVertical、LineThickHorizontal、LineThick 承接,参数里 size 控制像素粗度,style 接收 uint 型线型掩码,end_style 决定线头是平切还是圆头。 PolylineThick 与 PolygonThick 接收 int 数组引用 x[]、y[],适合把多个拐点一次性送进绘制栈;前者画开放折线,后者闭合填框。若拐点生硬,PolylineSmooth 和 PolygonSmooth 提供 tension=0.5、step=10 的默认 Catmull-Rom 类插值,step 每 10 像素插一个点,曲线视觉更顺。 FillRectangle 则退回到最简签名:只吃左上右下坐标加颜色,无尺寸与端样参数,说明填充块不走描边逻辑。开 MT5 把 size 从 1 改到 3,端样式切 LINE_END_ROUND,能直接看出黄金分时图支撑线在 4K 屏上的辨识度差异;外汇与贵金属波动剧烈,图形仅作辅助,实盘仍属高风险。
class="type">void LineThickVertical(class="kw">const class="type">int x,class="kw">const class="type">int y1,class="kw">const class="type">int y2,class="kw">const class="type">uint clr,class="kw">const class="type">int size,class="kw">const class="type">uint style,ENUM_LINE_END end_style); class="type">void LineThickHorizontal(class="kw">const class="type">int x1,class="kw">const class="type">int x2,class="kw">const class="type">int y,class="kw">const class="type">uint clr,class="kw">const class="type">int size,class="kw">const class="type">uint style,ENUM_LINE_END end_style); class="type">void LineThick(class="kw">const class="type">int x1,class="kw">const class="type">int y1,class="kw">const class="type">int x2,class="kw">const class="type">int y2,class="kw">const class="type">uint clr,class="kw">const class="type">int size,class="kw">const class="type">uint style,ENUM_LINE_END end_style); class="type">void PolylineThick(class="kw">const class="type">int &x[],class="kw">const class="type">int &y[],class="kw">const class="type">uint clr,class="kw">const class="type">int size,class="kw">const class="type">uint style,ENUM_LINE_END end_style); class="type">void PolygonThick(class="kw">const class="type">int &x[],class="kw">const class="type">int &y[],class="kw">const class="type">uint clr,class="kw">const class="type">int size,class="kw">const class="type">uint style,ENUM_LINE_END end_style); class=class="str">"cmt">//--- Methods for drawing a smoothed polyline and smoothed polygon class="type">void PolylineSmooth(class="kw">const class="type">int &x[],class="kw">const class="type">int &y[],class="kw">const class="type">uint clr,class="kw">const class="type">int size, ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND, class="type">class="kw">double tension=class="num">0.5,class="type">class="kw">double step=class="num">10); class="type">void PolygonSmooth(class="type">int &x[],class="type">int &y[],class="kw">const class="type">uint clr,class="kw">const class="type">int size, ENUM_LINE_STYLE style=STYLE_SOLID,ENUM_LINE_END end_style=LINE_END_ROUND, class="type">class="kw">double tension=class="num">0.5,class="type">class="kw">double step=class="num">10); class=class="str">"cmt">//--- Methods of drawing filled primitives class="type">void FillRectangle(class="type">int x1,class="type">int y1,class="type">int x2,class="type">int y2,class="kw">const class="type">uint clr);
在MT5图表上直接刷填充图形
做价格行为可视化时,光画边框不够,填充区域更能一眼看出支撑阻力带的密实程度。MQL5 的 Canvas 类提供了一组 Fill 开头的方法,可以在像素缓冲层直接上色,不依赖系统对象。 FillTriangle 吃三个顶点坐标加颜色值,适合把三角收敛区涂出来;FillPolygon 接收两个 int 数组引用(x[] 和 y[]),顶点数由数组长度决定,画不规则形态比逐个线省事。 FillCircle 和 FillEllipse 分别按半径和对角坐标填充,标注波段高低点附近的密集成交区很顺手。最后两个 Fill 重载最实用:单色 Flood 填充,或带 threshould 阈值做容差填充,避免抗锯齿边缘漏色。 外汇和贵金属波动快、跳空多,这类自绘层在高杠杆下仅作辅助参考,实际下单仍须结合风控,市场可能反向扫掉你的区域假设。
class="type">void FillTriangle(class="type">int x1,class="type">int y1,class="type">int x2,class="type">int y2,class="type">int x3,class="type">int y3,class="kw">const class="type">uint clr); class="type">void FillPolygon(class="type">int &x[],class="type">int &y[],class="kw">const class="type">uint clr); class="type">void FillCircle(class="type">int x,class="type">int y,class="type">int r,class="kw">const class="type">uint clr); class="type">void FillEllipse(class="type">int x1,class="type">int y1,class="type">int x2,class="type">int y2,class="kw">const class="type">uint clr); class="type">void Fill(class="type">int x,class="type">int y,class="kw">const class="type">uint clr); class="type">void Fill(class="type">int x,class="type">int y,class="kw">const class="type">uint clr,class="kw">const class="type">uint threshould);
◍ 画布像素格式与通道字节排布
在 CCanvas 的 CreateBitmap 与 CreateBitmapLabel 里,clrfmt 参数决定图形资源的像素格式,终端后续按该格式处理图表上的图像显示。可选常量来自 ENUM_COLOR_FORMAT:COLOR_FORMAT_XRGB_NOALPHA 忽略 alpha;COLOR_FORMAT_ARGB_RAW 保留原始 ARGB 不做终端处理;COLOR_FORMAT_ARGB_NORMALIZE 则由终端归一化处理颜色分量。 像素数组 m_pixels 中每个元素为 uint(4 字节),R、G、B、A 各占一字节,X 为未用字节。单字节取值范围 0–255,例如 R=255、G=0、B=0 得到纯红,G=255 其余为 0 得纯绿,B=255 得纯蓝;alpha 从 0(全透明)到 255(不透明)可控制重叠像素的可见性,这一套在 COLOR_FORMAT_ARGB_NORMALIZE 下才被正确解释。 十六进制里单字节写作 0x00 到 0xFF,对应十进制 0–255。十六进制用 A–F 表示 10–15,所以颜色字节如 0xFF0000 即 R 满、G/B 零。新手在 MT5 里改 CCanvas 颜色时,直接按这个映射填像素数组就能验证显示效果,外汇与贵金属图表叠加自定义画布属高频改动,注意终端渲染差异带来的高风险视觉误差。
「用 CCanvas 在 MT5 图表上画图形与文字」
在 MT5 里做自定义图表覆盖层,CCanvas 是最直接的对象。先建一个脚本 Erase.mq5,包含 Canvas.mqh 后实例化 CCanvas,把像素格式设成 COLOR_FORMAT_ARGB_NORMALIZE,调 Erase 填色再 Update(true),等 6 秒看效果,最后 Destroy 释放资源。这块铺底矩形就是后续复杂图形的地基。 像素格式差别很实:ARGB_NORMALIZE 下 alpha 写 0xFF 全不透明、0xCC 半透明;换 ARGB_RAW 同样 0xFF 看着没差,但 alpha 降到 0xFA 以下图像就明显失真——因为原始格式不做 RGB 归一化,通道值溢出 255 直接被丢,出伪影。代价是 RAW 比 NORMALIZE 渲染更快。XRGB_NOALPHA 则彻底无视 alpha,图像直接叠在图表上。 文字用 TextOut 方法。基础字号要乘 -10 转像素,比如 21 号字写 -210。想让标签居中,用 TextSize 取宽高,按图表尺寸反算 canvasX/canvasY,再 CreateBitmapLabel 定位。把格式切到 ARGB_RAW 且 alpha 设 0,就能在图表上方浮出文字而不重绘底图,等价于模拟 OBJ_LABEL。 图元绘制分三档:DrawPrimitives 无平滑只能 STYLE_SOLID;加 AA 前缀(LineAA、CircleAA 等)抗锯齿更顺滑;换 Wu 前缀质量再高一截;Thick 前缀多出 size 线宽与 end_style 线尾样式两个参数。最后 PolylineSmooth / PolygonSmooth 走 Bézier,带 tension 平滑度和 step 近似步数,运行时改这俩参数能实时看曲线形变。外汇贵金属图表叠加自绘层属高风险辅助,参数乱设可能遮住价格本身。