工具箱组件 画布(设计器类型名:画布;支持库:画布类)。
用于在窗口内做可交互的 2D 绘图:图形编辑、手绘笔迹、像素涂鸦、HUD 叠层、导出图片等。
配套样式说明见 yss/canvas.md。任意控件/窗口即时叠画见支持库 绘制类(与本页「画布类」不同:画布类管场景图元与像素层;绘制类可绑画布/组件/窗口做 QPainter 式叠画)。
硬约束
- 控件名来自窗口 XML,调用写
画布1.添加矩形(...)(方法必须带括号)。 - 鼠标事件坐标是控件坐标;
添加*/ 路径点用场景坐标(先控件到场景X/Y)。 - 即时 API(
画线/画矩形等)仅在绘制事件内有效;跨事件保留叠画请用 绘制类。 添加*失败返回图形 ID0;颜色文本#AARRGGBB/#RRGGBB。
1. 三种绘制层(先选对层)
从下到上每帧合成顺序为:
- 控件背景(设计器背景色等)
- 像素层(可选):整幅位图,适合涂鸦、贴图底图
- 场景层:带稳定 图形ID 的矢量/文本/图片节点,可点选、拖动、组合、持久化
- 即时层:只在
绘制事件里临时画一帧,帧末清空,不进场景、不可点选 - 推荐用独立对象 绘制类(变换/裁剪/线型);画布上的画线/画矩形等即时 API 在绘制帧内已走同一路径
| 需求 | 用哪一层 | 典型 API |
|---|---|---|
| 可点选的矩形、连线、图元 | 场景 | 添加矩形 / 添加直线 / … |
| 鼠标拖出自由曲线并保留 | 场景路径 | 开始路径 → 线到 → 结束路径 |
| 十字准星、临时辅助线、帧率文字 | 即时 | 绘制类 或仅在 绘制 里 画线 / 画文本 |
| 位图涂抹、导入照片当底 | 像素 | 锁定像素 / 置像素 / 从字节集载入 |
| 保存当前画面给人看 | 导出 | 导出PNG / 到字节集 |
| 保存可再编辑的工程内容 | 场景文本 | 导出场景 / 导入场景 |
颜色统一用文本:#AARRGGBB 或 #RRGGBB(如 "#FFFF0000" 不透明红,"#4080FF80" 半透明蓝)。
2. 坐标系(极易写错)
画布上有两套坐标,都不是窗口客户区绝对坐标:
| 名称 | 原点 | 用途 |
|---|---|---|
| 控件坐标 | 画布控件左上角 | 鼠标事件 X/Y、取命中、框选、取/置像素 |
| 场景坐标 | 内容坐标系(已含视图平移与缩放) | 添加*、置位置、路径点、移动选中 |
转换(传入的一对坐标是「点」的两个分量):
小数 sx = 画布1.控件到场景X(控件x, 控件y)
小数 sy = 画布1.控件到场景Y(控件x, 控件y)
小数 cx = 画布1.场景到控件X(场景x, 场景y)
小数 cy = 画布1.场景到控件Y(场景x, 场景y)
规则: 鼠标事件里先转场景再写入场景 API;取命中(X, Y) 直接用事件里的控件坐标。
视图:
- 中键拖:平移(属性「允许平移」)
- Ctrl+滚轮:缩放(属性「允许缩放」;「最小缩放」「最大缩放」为百分比,如 25 表示 0.25)
- 代码:
置视图(平移X, 平移Y, 缩放)/复位视图()/取平移X/取平移Y/取视图缩放 - 视图变化会触发事件
视图改变 - 选中集合变化会触发事件
选中改变(可用取选中数/取选中列表)
3. 编辑模式与默认鼠标行为
画布1.置编辑模式(1) // 1=选择+拖动(默认);0=关闭内置拖动(更适合纯手绘脚本)
当模式为 1 时(需先点击画布取得焦点):
| 操作 | 效果 |
|---|---|
| 左键点在图形上 | 选中;可拖动;单选显示缩放/旋转手柄 |
| Ctrl+点图形 | 追加或取消该项选中 |
| Shift+拖空白 | 框选;再按 Ctrl 为追加框选 |
| 空白处左键(无 Shift) | 不强制选中;脚本可在此手绘 |
| Delete / Backspace | 删除选中 |
| 方向键 | 微调 1 场景单位;Ctrl+方向键为 10 |
| Ctrl+C / X / V / D / A | 复制 / 剪切 / 粘贴 / 克隆 / 全选 |
拖动时默认 吸附 其它图形边/中线;可用 置吸附 / 置网格 调整。
4. 场景图形:创建与改属性
所有 添加* 返回 整数图形ID(失败为 0)。之后用 ID 改外观与位姿。
4.1 创建(场景坐标;返回整数图形 ID,失败 0)
| 方法 | 签名 | 返回 |
|---|---|---|
添加直线 |
整数 画布.添加直线(小数 x1, 小数 y1, 小数 x2, 小数 y2) |
整数 |
添加矩形 |
整数 画布.添加矩形(小数 x, 小数 y, 小数 宽, 小数 高) |
整数 |
添加椭圆 |
整数 画布.添加椭圆(小数 x, 小数 y, 小数 宽, 小数 高) |
整数 |
添加多边形 |
整数 画布.添加多边形(文本 点列) |
整数 |
添加文本 |
整数 画布.添加文本(小数 x, 小数 y, 文本 内容) |
整数 |
添加图片 |
整数 画布.添加图片(小数 x, 小数 y, 小数 宽, 小数 高, 文本 路径) |
整数 |
开始路径 |
整数 画布.开始路径(小数 x, 小数 y) |
整数 |
线到 |
逻辑 画布.线到(小数 x, 小数 y) |
逻辑 |
曲线到 |
逻辑 画布.曲线到(小数 c1x, c1y, c2x, c2y, x, y) |
逻辑 |
关闭路径 |
逻辑 画布.关闭路径() |
逻辑 |
结束路径 |
整数 画布.结束路径() |
整数 |
删除 |
逻辑 画布.删除(整数 图形ID) |
逻辑 |
清空 |
无 画布.清空() |
无 |
取数量 |
整数 画布.取数量() |
整数 |
是否存在 |
逻辑 画布.是否存在(整数 图形ID) |
逻辑 |
取图形列表 |
文本 画布.取图形列表() |
文本 |
多边形示例:
整数 id = 画布1.添加多边形("0,0;100,0;50,80")
画布1.置填充色(id, "#4080FF80")
画布1.置描边色(id, "#FFFFFFFF")
画布1.置线宽(id, 2)
路径手绘(与选择模式共存时:先判断未命中图形再起笔):
逻辑 g_画中 = 假
函数 画布1.鼠标按下(整数 X, 整数 Y, 逻辑 按下) {
如果 (画布1.取命中(X, Y) > 0) { 返回 }
小数 sx = 画布1.控件到场景X(X, Y)
小数 sy = 画布1.控件到场景Y(X, Y)
整数 id = 画布1.开始路径(sx, sy)
画布1.置描边色(id, "#FFFFEE88")
画布1.置线宽(id, 2)
g_画中 = 真
}
函数 画布1.鼠标移动(整数 X, 整数 Y, 逻辑 按下) {
如果 (g_画中 && 按下) {
画布1.线到(画布1.控件到场景X(X, Y), 画布1.控件到场景Y(X, Y))
}
}
函数 画布1.鼠标抬起(整数 X, 整数 Y, 逻辑 按下) {
如果 (g_画中) {
画布1.结束路径()
g_画中 = 假
}
}
4.2 外观与变换(均带图形 ID)
| 方法 | 签名 | 返回 | 说明 |
|---|---|---|---|
置填充色 |
无 置填充色(整数 ID, 文本 颜色) |
无 | |
取填充色 |
文本 取填充色(整数 ID) |
文本 | |
置描边色 |
无 置描边色(整数 ID, 文本 颜色) |
无 | |
取描边色 |
文本 取描边色(整数 ID) |
文本 | |
置线宽 |
无 置线宽(整数 ID, 小数 宽) |
无 | |
取线宽 |
小数 取线宽(整数 ID) |
小数 | |
置位置 |
无 置位置(整数 ID, 小数 x, 小数 y) |
无 | |
取位置X |
小数 取位置X(整数 ID) |
小数 | |
取位置Y |
小数 取位置Y(整数 ID) |
小数 | |
置尺寸 |
无 置尺寸(整数 ID, 小数 宽, 小数 高) |
无 | |
取宽度 |
小数 取宽度(整数 ID) |
小数 | |
取高度 |
小数 取高度(整数 ID) |
小数 | |
置旋转 |
无 置旋转(整数 ID, 小数 角度) |
无 | 度 |
取旋转 |
小数 取旋转(整数 ID) |
小数 | |
置缩放 |
无 置缩放(整数 ID, 小数 sx, 小数 sy) |
无 | |
取缩放X |
小数 取缩放X(整数 ID) |
小数 | |
取缩放Y |
小数 取缩放Y(整数 ID) |
小数 | |
置可见 |
无 置可见(整数 ID, 逻辑 可见) |
无 | |
取可见 |
逻辑 取可见(整数 ID) |
逻辑 | |
置锁定 |
无 置锁定(整数 ID, 逻辑 锁定) |
无 | |
取锁定 |
逻辑 取锁定(整数 ID) |
逻辑 | |
置Z序 |
无 置Z序(整数 ID, 整数 z) |
无 | 越大越靠上 |
取Z序 |
整数 取Z序(整数 ID) |
整数 | |
置标签 |
无 置标签(整数 ID, 文本 标签) |
无 | |
取标签 |
文本 取标签(整数 ID) |
文本 |
5. 选中、组合、对齐、剪贴板、层级
| 方法 | 签名 | 返回 | 说明 |
|---|---|---|---|
选中 |
无 选中(整数 图形ID, [逻辑 追加=假]) |
无 | |
取消选中 |
无 取消选中(整数 图形ID) |
无 | |
清空选中 |
无 清空选中() |
无 | |
全选 |
无 全选() |
无 | |
反选 |
无 反选() |
无 | |
是否选中 |
逻辑 是否选中(整数 图形ID) |
逻辑 | |
取选中数 |
整数 取选中数() |
整数 | |
取选中 |
整数 取选中(整数 索引) |
整数 | 从 0 |
取选中列表 |
文本 取选中列表() |
文本 | |
置编辑模式 |
无 置编辑模式(整数 模式) |
无 | 0关内置拖动 · 1选择+拖动(默认) |
取编辑模式 |
整数 取编辑模式() |
整数 | |
组合 |
整数 组合() |
整数 | ≥2 选中;返回组 ID |
取消组合 |
逻辑 取消组合([整数 组ID=0]) |
逻辑 | |
取父级 |
整数 取父级(整数 图形ID) |
整数 | |
是否组合 |
逻辑 是否组合(整数 图形ID) |
逻辑 | |
移动选中 |
无 移动选中(小数 dx, 小数 dy) |
无 | 场景位移 |
框选 |
整数 框选(小数 x1, y1, x2, y2, [逻辑 追加=假]) |
整数 | 控件坐标;返回新选中数 |
水平翻转 |
无 水平翻转() |
无 | |
垂直翻转 |
无 垂直翻转() |
无 | |
置吸附 |
无 置吸附(逻辑) |
无 | |
取吸附 |
逻辑 取吸附() |
逻辑 | |
置吸附容差 |
无 置吸附容差(小数) |
无 | 屏幕像素 |
取吸附容差 |
小数 取吸附容差() |
小数 | |
置网格 |
无 置网格(小数) |
无 | 场景单位;0=关 |
取网格 |
小数 取网格() |
小数 | |
对齐左 |
无 对齐左() |
无 | |
对齐右 |
无 对齐右() |
无 | |
对齐顶 |
无 对齐顶() |
无 | |
对齐底 |
无 对齐底() |
无 | |
水平居中 |
无 水平居中() |
无 | |
垂直居中 |
无 垂直居中() |
无 | |
水平分布 |
无 水平分布() |
无 | 至少 3 个选中 |
垂直分布 |
无 垂直分布() |
无 | 至少 3 个选中 |
删除选中 |
整数 删除选中() |
整数 | |
克隆选中 |
整数 克隆选中() |
整数 | |
复制选中 |
整数 复制选中() |
整数 | |
剪切选中 |
整数 剪切选中() |
整数 | |
粘贴 |
整数 粘贴() |
整数 | |
置顶 |
无 置顶() |
无 | |
置底 |
无 置底() |
无 | |
上移一层 |
无 上移一层() |
无 | |
下移一层 |
无 下移一层() |
无 | |
导出场景 |
文本 导出场景() |
文本 | YCANVAS\|1 开头 |
导入场景 |
整数 导入场景(文本 数据, [逻辑 清空=真]) |
整数 | 导入项数 |
画布1.选中(id)
画布1.选中(id2, 真)
整数 n = 画布1.框选(0, 0, 200, 150)
画布1.移动选中(10, 0)
整数 g = 画布1.组合()
6. 即时层(仅 绘制 事件)
画布内置即时 API(坐标为场景坐标):
| 方法 | 签名 | 返回 |
|---|---|---|
置笔触 |
无 画布.置笔触(文本 颜色, 小数 线宽) |
无 |
置填充 |
无 画布.置填充(文本 颜色) |
无 |
画线 |
无 画布.画线(小数 x1, 小数 y1, 小数 x2, 小数 y2) |
无 |
画矩形 |
无 画矩形(小数 x, 小数 y, 小数 宽, 小数 高) |
无 |
画椭圆 |
无 画椭圆(小数 x, 小数 y, 小数 宽, 小数 高) |
无 |
画文本 |
无 画布.画文本(小数 x, 小数 y, 文本 内容) |
无 |
勿在其它事件里调用上述即时 API。跨事件/绑任意组件叠画请用 绘制类:绘制类 g → g.绑画布(画布1) 或 g.绑组件(按钮1)。
函数 画布1.绘制() {
画布1.置笔触("#FFFFCC00", 1)
画布1.画线(0, 0, 50, 50)
画布1.置填充("#40FFFFFF")
画布1.画矩形(10, 10, 40, 30)
画布1.画椭圆(60, 10, 40, 30)
画布1.画文本(5, 5, "提示")
}
7. 像素层与导出画面
| 方法 | 签名 | 返回 | 说明 |
|---|---|---|---|
锁定像素 |
逻辑 锁定像素() |
逻辑 | |
解锁像素 |
逻辑 解锁像素() |
逻辑 | |
清空像素 |
逻辑 清空像素() |
逻辑 | |
取像素宽 |
整数 取像素宽() |
整数 | 未锁定时为 0 |
取像素高 |
整数 取像素高() |
整数 | 未锁定时为 0 |
取像素 |
文本 画布.取像素(小数 x, 小数 y) |
文本 | 控件坐标 |
置像素 |
逻辑 画布.置像素(小数 x, 小数 y, 文本 颜色) |
逻辑 | |
导出PNG |
逻辑 画布.导出PNG(文本 路径) |
逻辑 | 当前视图合成图 |
到字节集 |
字节集 画布.到字节集() |
字节集 | PNG |
从字节集载入 |
逻辑 画布.从字节集载入(字节集 数据) |
逻辑 | 替换像素缓冲 |
8. 场景持久化
文本 s = 画布1.导出场景()
到文件(取临时目录() + "scene.txt", s) // 按你项目里的文件 API 书写
文本 s2 = 到文本(读入文件(...)) // 读回文本
整数 n = 画布1.导入场景(s2, 真) // 真=先清空再导入;返回导入项数
导出场景 得到以 YCANVAS|1 开头的文本,含图形种类、位置、样式、组合关系、多边形点与路径点等,可供再次 导入场景 恢复可编辑内容。
若只要给人看的截图,用 导出PNG,不要用场景文本。
9. 事件
| 事件 | 参数 | 何时 |
|---|---|---|
绘制 |
无 | 每帧;写即时层 |
图形单击 |
整数 图形ID | 点中场景图形 |
图形双击 |
整数 图形ID | 双击图形 |
视图改变 |
无 | 平移/缩放变化后 |
选中改变 |
无 | 场景选中集合变化;可用 取选中数 / 取选中列表 |
鼠标按下 |
整数 X, 整数 Y, 逻辑 按下 | 控件坐标 |
鼠标移动 |
整数 X, 整数 Y, 逻辑 按下 | 控件坐标 |
鼠标抬起 |
整数 X, 整数 Y, 逻辑 按下 | 控件坐标 |
函数 画布1.选中改变() {
输出("选中数=", 画布1.取选中数())
}
函数 画布1.图形单击(整数 图形ID) {
输出("点中", 图形ID)
}
10. 设计器属性(画布专用)
| 面板标题 | 含义 | 语言读写 |
|---|---|---|
| 抗锯齿 | 绘制是否抗锯齿 | 画布1.抗锯齿 |
| 允许平移 | 是否允许中键拖视图 | 画布1.允许平移 |
| 允许缩放 | 是否允许 Ctrl+滚轮缩放 | 画布1.允许缩放 |
| 最小缩放 / 最大缩放 | 缩放范围(百分比整数,25=0.25 倍) | 画布1.最小缩放 / 最大缩放 |
另有通用:背景色、边框、停靠等(语言侧亦可读写 背景色 / 显示边框 / 边框大小 / 边框颜色)。
11. 按需求对照写法(速查)
| 用户需求 | 建议写法 |
|---|---|
| 流程图/框图可拖可组合 | 场景 添加矩形+添加直线;模式 1;组合/对齐* |
| 签字板/随手画 | 模式 1 + 空白处路径手绘;或模式 0 专心手绘 |
| 游戏 HUD / 准星 | 仅 绘制 里即时绘制 |
| 像素画板 | 锁定像素+置像素;可再叠场景 |
| 打开图片当底图 | 从字节集载入 或 添加图片 |
| 保存作品给人看 | 导出PNG |
| 保存工程可再编辑 | 导出场景 / 导入场景 |
| 多选批量移动 | 框选 或 Ctrl 点选后 移动选中 |
| 对齐一排按钮图元 | 多选后 对齐顶+水平分布 |
| 读图元当前样式/位姿 | 取填充色 / 取位置X / 取旋转 等 |
12. 完整方法一览(画布类)
场景结构: 清空 添加直线 添加矩形 添加椭圆 添加多边形 添加文本 添加图片 开始路径 线到 曲线到 关闭路径 结束路径 删除 取数量 是否存在 取图形列表
外观变换: 置填充色 置描边色 置线宽 置位置 置尺寸 置旋转 置缩放 置可见 置锁定 置Z序 置标签
取填充色 取描边色 取线宽 取位置X 取位置Y 取宽度 取高度 取旋转 取缩放X 取缩放Y 取可见 取锁定 取Z序 取标签
坐标视图: 取命中 控件到场景X/Y 场景到控件X/Y 置视图 复位视图 取平移X 取平移Y 取视图缩放
即时: 置笔触 置填充 画线 画矩形 画椭圆 画文本
像素导出: 锁定像素 解锁像素 清空像素 取像素宽/高 取/置像素 导出PNG 到字节集 从字节集载入
选区编辑: 选中 取消选中 清空选中 是否选中 取选中数 取选中 取选中列表 置/取编辑模式 组合 取消组合 取父级 是否组合 移动选中 全选 反选 框选 水平/垂直翻转
吸附对齐: 置/取吸附 置/取吸附容差 置/取网格 对齐左/右/顶/底 水平/垂直居中 水平/垂直分布
剪贴板层级: 删除选中 克隆选中 复制选中 剪切选中 粘贴 置顶 置底 上移一层 下移一层
场景文本: 导出场景 导入场景