VisualHMI - 画图
本章节主要介绍LUA脚本使用API进行线、矩形、圆、椭圆、文字、图片等
适用范围:VisualHMI - HMI&M系列&Dx系列
例程下载链接:ViusalHMI - 画图(点击下载)
1.Lua API说明
3.1.on_draw(screen,control)
on_draw 是 HMI 系统提供的控件级自绘回调接口,用于在指定画面的特定控件区域上执行用户自定义的图形绘制。开发者可on_draw函数里调用各类 draw_xxx 图形 API,实现图片、文字、图形(点、线、几何图形)的绘制
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
screen_id |
number | 当前画面 ID • 表示触发重绘的界面编号 • 可用于区分不同画面的绘制逻辑 |
control_id |
number | 触发重绘的控件 ID • 表示需要自绘的控件唯一标识 • 必须 ≠ 0 |
⚠️ 注意:
- 该函数为系统回调函数,用户不得直接调用;
- 所有
draw_xxx图形绘制指令(如draw_line、draw_surface等)必须在此函数内调用才能生效; - 控件ID ≠ 0 ,否则自绘功能无效。
3.1.1.触发条件 on_draw
界面包含动画、视频、RTC 时间等动态元素刷新;
用户触摸或操作屏幕控件;
脚本通过
set_xxx更新控件属性;串口/LUA 指令修改寄存器,从而修改控件状态;
主动调用
redraw()
3.1.2. 多图层绘制机制
核心原理
HMI 系统采用控件 Z 轴顺序(即界面编辑器中的控件叠放顺序)作为天然的图层管理机制。on_draw(screen_id, control_id) 回调函数在每个可重绘控件独立触发,开发者可通过判断 control_id,将不同的图形内容绘制到对应控件图层(控件叠放上下关系),从而实现逻辑上的“分层叠加”。
✅ 关键设计:控件在界面中的上下排列顺序直接决定了最终视觉的图层叠加顺序。
典型图层结构示例
假设界面从底到顶包含以下元素(Z 轴顺序由低到高):
| 图层层级 | 元素类型 | 实现方式 | 作用 |
|---|---|---|---|
| 下层 | 蓝色背景区域 | ID = 10 的矩形控件(蓝色填充) | 作为“水果图层”的容器 |
| 上层 | 黄色背景区域 | ID = 11 的矩形控件(黄色填充) | 作为“小岛图层”的容器 |
📌 注意:
- 蓝色矩形(ID=10)在编辑器中位于黄色矩形(ID=11)下方,因此视觉上被后者部分覆盖;
- 两个矩形均启用自绘功能(ID ≠ 0),系统将在各自区域触发
on_draw。

当系统刷新界面时:
- 遍历所有需重绘的控件(按 Z 轴从底到顶);
- 对每个支持自绘的控件,调用一次
on_draw(screen_id, control_id); - 开发者通过
control_id判断当前绘制目标:- 若
control_id == 10→ 在蓝色矩形区域内绘制“水果图片”; - 若
control_id == 11→ 在黄色矩形区域内绘制“小岛图片”;
- 若
- 最终合成效果: 原本画面(底) ← 蓝色背景 + 水果(中) ← 黄色背景 + 小岛(顶)

function on_draw(screen_id, control_id)
if screen_id == 0 and control_id == 1
then
draw_surface(surface[1], 293, 88, 222, 353, 0, 0) --裁剪显示
elseif screen_id == 0 and control_id == 2
then
draw_surface(surface[2], 314, 158, 180, 250, 0, 0) --裁剪显示
end
end
3.2.redraw()
全局界面重绘触发函数,redraw() 是 HMI 系统提供的全局重绘请求接口,用于主动触发当前画面所有支持自绘的控件执行 on_draw 回调函数,强制刷新界面显示内容。
3.3.set_pen_color(color)
设置绘图画笔颜色,set_pen_color(color) 是 HMI 系统提供的设置画笔颜色函数,用于设置后续所有绘图操作的前景色(画笔颜色),适用于线条、矩形边框、圆形轮廓、文本描边等非填充型或边框型图形的颜色。
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
color |
number | 画笔颜色值(RGB565 格式) • 高 5 位为 Red(0~31) • 中 6 位为 Green(0~63) • 低 5 位为 Blue(0~31) • 取值范围: 0x0000(黑)至 0xFFFF(白) • 用于后续 draw_line、draw_rect、draw_circle 等矢量图形的边框或线条颜色 |
RGB565 编码示例:
| 颜色 | RGB (888) | RGB565 (Hex) | Lua 常量建议 |
|---|---|---|---|
| 红色 | (255, 0, 0) | 0xF800 |
COLOR_RED = 0xF800 |
| 绿色 | (0, 255, 0) | 0x07E0 |
COLOR_GREEN = 0x07E0 |
| 蓝色 | (0, 0, 255) | 0x001F |
COLOR_BLUE = 0x001F |
| 白色 | (255,255,255) | 0xFFFF |
COLOR_WHITE = 0xFFFF |
| 黑色 | (0, 0, 0) | 0x0000 |
COLOR_BLACK = 0x0000 |
3.4.draw_line(x0,y0,x1,y1,width)
直线绘制函数,draw_line 是 HMI 绘制一条指定起点、终点及线宽的直线段。该线段颜色依赖当前画笔颜(由 set_pen_color 设定)
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
x0 |
number | 起始点 X 轴坐标: 直线起点的水平位置,取值范围依据实际屏幕分辨率而定 |
y0 |
number | 起始点 Y 轴坐标: 直线起点的垂直位置,取值范围依据实际屏幕分辨率而定 |
x1 |
number | 结束点 X 轴坐标 :直线终点的水平位置,取值范围依据实际屏幕分辨率而定 |
y1 |
number | 结束点 Y 轴坐标 :直线终点的垂直位置,取值范围依据实际屏幕分辨率而定 |
width |
number | 线条的厚度: 表示绘制直线时线条的宽度,有效取值范围为 1 到 10 |
3.5.draw_rect(x0,y0,x1,y1,fill)
矩形绘制函数,draw_rect 函数是HMI(人机交互界面)开发中常用的绘图接口之一,通过定义左上角和右下角的坐标以及是否填充该矩形,在指定位置绘制一个矩形。
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
x0 |
number | 左上角 X 坐标 • 相对于绘图上下文原点(通常是控件或画布的左上角)的水平偏移量 |
y0 |
number | 左上角 Y 坐标 • 相对于绘图上下文原点的垂直偏移量 |
x1 |
number | 右下角 X 坐标 • 定义矩形宽度的结束位置 |
y1 |
number | 右下角 Y 坐标 • 定义矩形高度的结束位置 |
fill |
integer | 填充标志 • 若值为 1,则使用当前填充色填充整个矩形• 若值为 0,仅绘制矩形边框 |
3.6.draw_rect_alpha(x0,y0,x1,y1,alpha)
半透明实心矩形绘制函数,draw_rect_alpha 是 HMI 图形系统提供的半透矩形填充绘图接口,用于指定位内绘制一个带有指定透明度的实心矩形。该函数常用于实现遮罩层
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
x0 |
number | 矩形左上角 X 坐标 • 相对于当前控件客户区左上角的像素偏移 • 通常 ≥ 0 |
y0 |
number | 矩形左上角 Y 坐标 •相对于当前控件客户区左上角的像素偏移 • 通常 ≥ 0 |
x1 |
number | 矩形右下角 X 坐标 • 必须 > x0,否则矩形无效或不可见 |
y1 |
number | 矩形右下角 Y 坐标 • 必须 > y0,否则矩形无效或不可见 |
alpha |
number | 透明度系数 • 有效范围:0 ~ 255 • 0 = 完全透明(不可见) • 255= 完全不透明 • 中间值实现与背景的 Alpha 混合 |
3.7.draw_circle(x,y,r,fill)
圆形绘制函数,draw_circle 是用于绘制圆形的函数。此函数可以基于提供的中心坐标 (x, y)、半径 r 以及填充标志 fill 来绘制一个指定大小和样式的圆形。根据 fill 参数的不同,该函数可以绘制出轮廓圆(非填充)或实心圆(填充)
📊 参数说明
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
x |
数字 | - | 圆的中心点 X 坐标 |
y |
数字 | - | 圆的中心点 Y 坐标 |
r |
数字 | - | 圆的半径,决定了圆的大小 |
fill |
数字 | 0 | 填充标志: • 0 表示填充圆(实心圆)• 非 0 表示绘制圆周线(空心圆),此时值可作为线条厚度 |
3.8.draw_ellipse(x0,y0,x1,y1,fill)
椭圆绘制函数,draw_ellipse 是 HMI 图形系统提供椭圆绘图接口,用于绘制一个内切于指定矩形区域的椭圆。通过控制填充模式与边框表现,可灵活实现从实心椭圆到带厚度轮廓的空心椭圆
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
x0 |
number | 外接矩形左上角 X 坐标 |
y0 |
number | 外接矩形左上角 Y 坐标 |
x1 |
number | 外接矩形右下角 X 坐标 • 必须 > x0 |
y1 |
number | 外接矩形右下角 Y 坐标 • 必须 > y0 |
fill |
number | 填充控制标志 • 0:绘制实心填充椭圆 • 非 0:绘制空心椭圆轮廓,其值通常表示线条厚度(如 fill=2 表示 2 像素粗的边框) |
3.9.draw_image(image_id,frame_id,dstx,dsty,width,height,srcx,srcy)
图片绘制函数,draw_image 是 HMI系统提供绘制图片资源的接口。此函数允许开发者通过指定图片资源ID、显示位置与大小,以及可选的裁剪区域来灵活地控制图像显示。
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
image_id |
number | 图片资源的唯一标识符 • 标识将要绘制的图片资源; |
frame_id |
number | 帧ID • 对于支持帧动画的图片类型,指明所使用的具体帧; • 对于非动画图片类型,该值通常固定为0; |
dstx |
number | 图片显示的X坐标 • 目标图片左上角相对于客户区左上角的水平偏移量; |
dsty |
number | 图片显示的Y坐标 • 目标图片左上角相对于客户区左上角的垂直偏移量; |
width |
number | 图片显示的宽度 • 指定图片在屏幕上显示时的宽度,实现缩放效果; |
height |
number | 图片显示的高度 • 指定图片在屏幕上显示时的高度,实现缩放效果; |
srcx |
number | 图片裁剪的起始X坐标 • 若不希望从图片的原点开始绘制,可以指定从原图的哪个点开始裁剪; |
srcy |
number | 图片裁剪的起始Y坐标 • 配合 srcx,定义裁剪矩形的起点; |
[!note|tip:如何确定image_id] 1.在工程目录下的../build/文件夹,打开image.xml文件,image id = "xx"表示第一个参数

3.10.draw_text(text,x,y,w,h,font_id,size,color,align,charcode)
文本绘制函数,draw_text 是 HMI 图形系统提供的文字绘制接口,用于在指定区域内绘制字符串。支持自定义字体、字号、颜色、对齐方式及字符编码。
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
text |
string | 待显示的文本内容 • 支持 ASCII 及多字节字符(如 UTF-8、GB2312),具体由 charcode 决定 |
x |
number | 文本区域左上角 X 坐标 |
y |
number | 文本区域左上角 Y 坐标 |
w |
number | 文本区域宽度(像素) |
h |
number | 文本区域高度(像素) |
font_id |
number | 字体资源 ID • 对应工程中预加载的字体编号(如 0=默认字体,1=自定义矢量字体) |
size |
number | 字体大小(像素) • 表示字体高度 |
color |
number | 文字颜色(RGB565 格式) • 高 5 位 Red,中 6 位 Green,低 5 位 Blue • 例如: 0xFFFF = 白色,0x0000 = 黑色 |
align |
number | 文本对齐方式 • 常见值: 0 = 左对齐 1 = 居中对齐 2 = 右对齐 • 部分平台支持垂直对齐组合(需查手册) |
charcode |
number | 字符编码类型 • 指定 text 字符串的编码格式,选填。0 或不填,默认 lua 文件 UTF-8 编。1 位 GBK |
3.11.load_surface (filename)
图像加载函数,load_surface 用于从指定路径加载 JPEG 或 PNG 格式的图片文件(外部图形,非工程打包的image.bin里的图片资源),并将其作为句柄(surface)返回。surface后续绘图操作中被引用。
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
filename |
string | 待加载的图片文件路径: 支持的格式,JPEG, PNG |
⚠️ 关键注意事项
- 路径准确性:确保提供的
filename路径准确无误,指向有效的 JPEG 或 PNG 文件。 - 内存占用:大尺寸图像或大量图像的同时加载会占用较多内存,应注意资源管理。
- 透明度处理:对于带有透明度信息的 PNG 图像,占用内存比较大
3.12.destroy_surface (surface)
图层资源销毁函数,destroy_surface(surface) 用于释放“由 load_surface ”申请的图形资源。调用后,该图层指针失效,不可再用于任何绘图操作
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
surface |
number | 图层资源句柄 • 由 load_surface()、函数返回的有效指针或对象引用 |
✅ 核心用途:
- 防止内存泄漏,尤其在动态加载/卸载图片的场景中;
- 释放 GPU 或帧缓冲区中缓存的图像数据;
- 管理有限的嵌入式系统图形资源。
3.13.destroy_all_surface()
批量销毁所有图层资源函数,destroy_all_surface() 是 HMI 图形系统提供的全局图层资源清理接口,用于一次性释放当前脚本上下文中所有已加载的图层(surface)所占用的内存资源。调用后,所有通过 load_surface创建的图层句柄均失效
✅ 核心用途:
- 快速回收全部图像资源,避免逐个管理;
- 简化资源管理逻辑,防止因遗漏导致的内存泄漏。
3.14.draw_surface (surface,dstx,dsty,width,height,srcx,srcy)
draw_surface是绘制由load_surface 申请的图片资源 的接口,将已加载的图层资源(如 JPEG/PNG 图片)绘制到指定位置。支持区域裁剪与尺寸缩放。该函数必须在 on_draw 回调中调用才能生效。
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
surface |
number | 图层资源句柄 • 由 load_surface() 返回的有效图像对象 |
dstx |
number | 目标显示区域左上角 X 坐标 |
dsty |
number | 目标显示区域左上角 Y 坐标 |
width |
number | 目标显示宽度(可选) • 原图将水平缩放至该宽度 • 若省略或设为 0,使用原图宽度 |
height |
number | 目标显示高度(可选) • 原图将垂直缩放至该高度 • 若省略或设为 0,使用原图高度 |
srcx |
number | 源图裁剪起始 X 坐标(可选) • 从原图 (srcx, srcy) 开始截取内容 • 若省略或设为 0,从原图左上角开始 |
srcy |
number | 源图裁剪起始 Y 坐标(可选) • 配合 srcx 定义裁剪起点 • 若省略或设为 0,从原图左上角开始 |
3.15.get_surface_size (surface)
获取图层尺寸函数,get_surface_size(surface) 是 HMI 图形系统提供的图层属性查询接口,用于获取已加载图层(surface)的原始像素尺寸。该函数返回图像的宽度和高度
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
surface |
number | 图层资源句柄 • 由 load_surface() 返回的有效图像对象 |
3.16.clear_image_buffer()
清除内部图片资源缓存函数,clear_image_buffer() 是 HMI 系统提供的全局图像缓存管理接口,用于强制释放图形的图片数据,以降低内存占用
3.17.screen_shoot(filepath)
屏幕截图函数,screen_shoot(filepath) 是 HMI 系统提供的屏幕内容捕获接口,用于将当前显示画面(或指定区域)保存为图像文件( JPEG 格式)
📊 参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
filepath |
string | 截图保存的完整文件路径 • 必须包含文件名及扩展名(如 1.jpg ) |
2.工程配置
2.1.绘制键设置
添加15个字设置按钮,用于触发Lua绘制按钮,以“直线”按钮为例,控件配置如下所示:
- 写入地址:LW6100
操作模式:写入常量
- 常量值:1/2/3/4/5/6/7/8/9/10/11/12/13/14/15(依次为直线/矩形/半透矩形/圆/椭圆/图片ID/文字/屏内图片/销毁图片/销毁所有图片/获取图大小/视频窗口截图/屏幕截图/画SD图/画U盘图片)
- 使用图库:√
- 使用文字:√

2.2.画笔设置
添加15个位状态指示灯,用来设置画笔颜色,黄色/蓝色之前切换,如下所示:
- 写入地址:LW6100
- 切换开关:√
- 开关类型:切换开关

2.3.文本设置
添加一个文本控件,用于显示图片大小,配置如下所示:

3.Lua 脚本
3.1.画笔
在on_update里面,判断触发地址和键值,若地址为LW6100,值为0画笔为蓝色,值为1画笔为红色,代码如下所示:
penColor = {0xF800, 0x001F}
CUR_COLOR = 0xF800 --初始颜色,
function on_update(slave,vtype,addr)
if addr == 0x6100
then
CUR_COLOR = penColor[get_uint16(VT_LW, addr) + 1]
end
redraw()
end
function on_draw(screen_id,control_id)
set_pen_color(CUR_COLOR)
end
3.2.直线
3.2.1.Lua
在on_update里面,判断触发地址和键值,若地址为LW6101,值为1,绘制直线,代码如下所示:
mode = { --绘制类型表
line = 1,
rect = 2,
rect_alpha = 3,
circle = 4,
ellipse = 5,
imageId = 6,
text = 7,
surface_path3 = 8,
destroyOne = 9,
destroyAll = 10,
getSurface = 11,
videoShoot = 12,
screenShoot = 13,
surface_pathsd = 14,
surface_pathusb = 15
}
function on_update(slave,vtype,addr)
if addr == 0x6100
then
CUR_COLOR = penColor[get_uint16(VT_LW, addr) + 1]
elseif addr == 0x6101
then
local msg = ''
draw_type = get_uint16(VT_LW, addr) -- 键值
end
redraw()
end
function on_draw(screen_id,control_id)
set_pen_color(CUR_COLOR)
local switch = {
[mode.line] = function(control) -- 键值为1
draw_line(225, 253, 405, 253)
draw_line(508, 128, 508, 378, 5)
end,
}
if switch[draw_type]
then
switch[draw_type](control)
end
end
3.2.2.预览
运行预览,点击直线按钮,绘制宽度为1,和宽度为5的直线,设置画笔颜色,直线颜色随着改变,如下所示:

3.3.矩形
3.3.1.Lua
在on_update里面,判断触发地址和键值,若地址为LW6101,值为2,绘制矩形,代码如下所示:
mode = { --绘制类型表
line = 1,
rect = 2,
rect_alpha = 3,
circle = 4,
ellipse = 5,
imageId = 6,
text = 7,
surface_path3 = 8,
destroyOne = 9,
destroyAll = 10,
getSurface = 11,
videoShoot = 12,
screenShoot = 13,
surface_pathsd = 14,
surface_pathusb = 15
}
function on_update(slave,vtype,addr)
if addr == 0x6100
then
CUR_COLOR = penColor[get_uint16(VT_LW, addr) + 1]
elseif addr == 0x6101
then
local msg = ''
draw_type = get_uint16(VT_LW, addr) -- 键值
end
redraw()
end
function on_draw(screen_id,control_id)
set_pen_color(CUR_COLOR)
local switch = {
[mode.rect] = function(control) --键值2
draw_rect(225, 128, (225+180), (128+250), 0)--填充
draw_rect(418, 163, (418+180), (128+180), 1)--不填充
end,
}
if switch[draw_type]
then
switch[draw_type](control)
end
end
3.3.2.预览
运行预览,点击矩形按钮,绘制1个填充,1个不填充的矩形,设置画笔颜色,矩形颜色随着改变,如下所示:

3.4.半透矩形
3.4.1.Lua
在on_update里面,判断触发地址和键值,若地址为LW6101,值为3,绘制半透矩形,代码如下所示:
mode = { --绘制类型表
line = 1,
rect = 2,
rect_alpha = 3,
circle = 4,
ellipse = 5,
imageId = 6,
text = 7,
surface_path3 = 8,
destroyOne = 9,
destroyAll = 10,
getSurface = 11,
videoShoot = 12,
screenShoot = 13,
surface_pathsd = 14,
surface_pathusb = 15
}
function on_update(slave,vtype,addr)
if addr == 0x6100
then
CUR_COLOR = penColor[get_uint16(VT_LW, addr) + 1]
elseif addr == 0x6101
then
local msg = ''
draw_type = get_uint16(VT_LW, addr) -- 键值
end
redraw()
end
function on_draw(screen_id,control_id)
set_pen_color(CUR_COLOR)
local switch = {
[mode.rect_alpha] = function(control)--键值3
draw_rect_alpha(225, 128, (225+180), (128+250), 200)--0~255透明度
draw_rect_alpha(418, 163, (418+180), (128+180), 230)--0~255透明度
end,
}
if switch[draw_type]
then
switch[draw_type](control)
end
end
3.4.2.预览
运行预览,点击矩形按钮,绘制两个半透矩形,1个200透明度,1个230透明度,设置画笔颜色,半透矩形颜色随着改变,如下所示:

3.5.圆形
3.5.1.Lua
在on_update里面,判断触发地址和键值,若地址为LW6101,值为4,绘制圆形,代码如下所示:
mode = { --绘制类型表
line = 1,
rect = 2,
rect_alpha = 3,
circle = 4,
ellipse = 5,
imageId = 6,
text = 7,
surface_path3 = 8,
destroyOne = 9,
destroyAll = 10,
getSurface = 11,
videoShoot = 12,
screenShoot = 13,
surface_pathsd = 14,
surface_pathusb = 15
}
function on_update(slave,vtype,addr)
if addr == 0x6100
then
CUR_COLOR = penColor[get_uint16(VT_LW, addr) + 1]
elseif addr == 0x6101
then
local msg = ''
draw_type = get_uint16(VT_LW, addr) -- 键值
end
redraw()
end
function on_draw(screen_id,control_id)
set_pen_color(CUR_COLOR)
local switch = {
[mode.circle] = function(control)--键值4
draw_circle(300, 253, 100, 0) --填充
draw_circle(450, 253, 150, 1) --不填充
}
end,
if switch[draw_type]
then
switch[draw_type](control)
end
end
3.5.2.预览
运行预览,点击圆形按钮,绘制1个填充,1个不填充的圆形,设置画笔颜色,圆形颜色随着改变,如下所示:

3.6.椭圆
3.6.1.Lua
在on_update里面,判断触发地址和键值,若地址为LW6101,值为5,绘制椭圆,代码如下所示:
mode = { --绘制类型表
line = 1,
rect = 2,
rect_alpha = 3,
circle = 4,
ellipse = 5,
imageId = 6,
text = 7,
surface_path3 = 8,
destroyOne = 9,
destroyAll = 10,
getSurface = 11,
videoShoot = 12,
screenShoot = 13,
surface_pathsd = 14,
surface_pathusb = 15
}
function on_update(slave,vtype,addr)
if addr == 0x6100
then
CUR_COLOR = penColor[get_uint16(VT_LW, addr) + 1]
elseif addr == 0x6101
then
local msg = ''
draw_type = get_uint16(VT_LW, addr) -- 键值
end
redraw()
end
function on_draw(screen_id,control_id)
set_pen_color(CUR_COLOR)
local switch = {
[mode.ellipse] = function(control)--键值5
draw_ellipse(225, 128, (225+180), (128+250), 0)--填充
draw_ellipse(418, 163, (418+180), (128+180), 1)--不填充
}
end,
if switch[draw_type]
then
switch[draw_type](control)
end
end
3.6.2.预览
运行预览,点击椭圆按钮,绘制1个填充,1个不填充的椭圆,设置画笔颜色,椭圆颜色随着改变,如下所示:
