aardio 文档

canvas 动效画布

canvas 是给游戏、动画和自绘界面用的控件。自绘事件和动画接口与 plus 控件 相同(onDrawBackground、onDrawForeground、onDrawComplete、startAnimation、onAnimation,鼠标键盘事件也一样),plus 的自绘代码把 cls="plus" 换成 cls="canvas" 一般就能运行。

plus canvas
画布 每次重绘新建内存位图,伽马校正合成 常驻的 PARGB 内存位图(GDI+ 最快的格式),默认合成
动画节拍 窗口定时器,帧间隔不稳 跟随显示器刷新(60Hz 屏幕 16.7 毫秒,高刷屏更快)
功能 文本、图标、皮肤、边框、圆角、进度条…… 只有画布、鼠标键盘事件与动画
透明 剪切父窗口背景 不透明;orphanWindow(true) 后为透明分层窗口

见缝插针小游戏实测(200% DPI,880×1360 像素):plus 每帧绘图 24 毫秒、帧间隔约 31 毫秒;canvas 每帧 5 毫秒、帧间隔 16.7 毫秒。带整屏半透明遮罩的结算画面 plus 约 10 帧/秒,canvas 仍是 60 帧/秒。

游戏、动画和大量自绘一律用 canvas;按钮、图标文字、贴图等普通界面控件用 plus。canvas 上不要叠放其他控件,按钮直接画在画布上更好看(命中检测自己做);确实需要叠放时,对上层控件调用 orphanWindow(true)。

aardio 窗体设计器控件控工具箱控件排序:指针(用于在设计器上拖动控件),static,plus,canvas... , 第 3 个控件就是 canvas 。在控件工具箱中点选 canvas,然后在窗体设计器上拖动选好位置放置控件即可。canvas 在设计器中默认会设为白色背景。

最小示例

import win.ui;
/*DSG{{*/
var winform = win.form(text="canvas";right=599;bottom=399)
winform.add(
canvas={cls="canvas";left=0;top=0;right=600;bottom=400;bgcolor=0x2A1A12;anchors={left=1;top=1;right=1;bottom=1};z=1}
)
/*}}*/

var x = 0;
var brush = gdip.solidBrush(0xFF4CC9F0);

winform.canvas.onDrawForeground = function(graphics,rc){
    var dpi = winform.dpiScale(1);
    graphics.scale(dpi,dpi); //之后按 100% DPI 的逻辑坐标绘图
    graphics.fillCircle(brush,x,200,30);
}

winform.canvas.onAnimation = function(prevState,beginning,change,timestamp,duration,deltaMs){
    x = (timestamp * 0.2) % 600; //按时间推进,不要按帧计数
    return true; //返回 null 才停止(返回 false 不停止)
}

winform.onDestroy = function(){ brush.delete(); }

winform.canvas.startAnimation(); //省略间隔:每帧回调
winform.show();
win.loopMessage();

范例都在 ~/examples/canvas/ 目录:balls.aardio(弹跳小球)、game/(见缝插针等 10 个小游戏)、weather-card.aardio(动画天气卡片)、clock.aardio(透明分层窗口做的桌面时钟);~/examples/plus/av/celebrate.aardio 是盖在控件上面的透明特效层。

绘图

动画

鼠标与键盘

事件由 win.ui.tracker 提供,与 plus 启用 notify 后相同:onMouseDown、onMouseUp、onMouseClick、onMouseMove、onMouseDrag、onMouseWheel、onKeyDown、onKeyUp、onFocusGot、onFocusLost 等。notify 默认为 true,一般不用写;设为 false 时鼠标穿透到下层窗口(例如父窗体),适合纯装饰的背景动画,运行时也可以修改。点击画布会自动获得键盘焦点。

画布默认接收方向键与字符键;要接收回车、Tab、Esc 设置 winform.canvas.dlgCode = 4/*_DLGC_WANTALLKEYS*/。cursor 属性可以换鼠标指针,例如 "hand"。

透明特效层

调用 orphanWindow(true) 后画布转为透明分层窗口,背景默认全透明,可以盖在其他控件上面画粒子。鼠标要穿透到下面的控件时加上 _WS_EX_TRANSPARENT:

winform.add(fx={cls="canvas";left=0;top=0;right=600;bottom=400;anchors={left=1;top=1;right=1;bottom=1};z=99});
winform.fx.orphanWindow(true); //在 winform.show() 之前调用
winform.fx.modifyStyleEx(,0x20/*_WS_EX_TRANSPARENT*/);

分层模式下文字不要用 ClearType(默认的抗锯齿即可)。

分层模式也能做任意形状的窗口:clock.aardio 的画布铺满一个无边框窗体后调用 orphanWindow(true),表盘缓存成位图,每帧只重画指针,圆形之外全透明;窗体本身用 win.ui.layered 变成全透明,只负责定位和拖动。

截图与无界面测试

snap() 立即绘制一帧并返回副本(PARGB 格式的 gdip.bitmap),不依赖窗口显示,隐藏的窗口也能截图,适合无界面测试。用完要 delete。

var bmp = winform.canvas.snap();
var argb = bmp.getPixel(10,10);
bmp.delete();

录制视频

画布的内存布局与 sys.mediaFoundation 视频写入器要求的帧一致(PARGB、自上而下、步幅为宽×4)。在 onDrawComplete 里把 owner.bitmap 传给写入器即可录下每一帧(画布尺寸必须与视频一致):

winform.canvas.onDrawComplete = function(graphics,rc,hMemBitmap){
    if(writer) writer.writeFrame(owner.bitmap);
}

owner.bitmap 在画布尺寸改变时会重建,不要长期保存或删除它。

音效

游戏音效用 sys.soundPool:启动时载入,之后一句 play(名字),多个声音可以同时响,不卡画面。

Markdown 格式