02 exeasyui单组件演示
作者:沈园园 | 最后修改:2026-04-20
一、概述
本项目是基于 exeasyui 图形用户界面扩展库的完整组件演示程序,展示了 20 种不同的 UI 组件和功能模块。每个演示模块独立运行,通过主程序统一调度管理。
airui 是基于 LVGL 9.4 版本进行图形层封装的 LuatOS 核心库,把常用组件、事件管理、输入和基础视觉主题封装为更易上手的 Lua 接口,便于在支持 LuatOS 的设备和 PC 上统一开发。
建议使用airui来开发显示界面,airui demo参考:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/ui/airui/single
二、演示功能概述
2.1 系统核心模块
1、main.lua - 主程序入口模块
- 项目初始化和版本定义
- 系统任务调度和管理
- 看门狗配置和系统监控
- 演示模块的选择和加载
- 提供统一的程序启动入口
2、ui_main.lua - 用户界面主控模块
- 多页面管理和切换逻辑
- 触摸事件分发和处理
- 界面渲染调度
- 主题管理和配置
- 提供完整的用户交互体验
3、hw_font_drv.lua - 默认使用字体、lcd显示、tp触摸初始化驱动模块
- 统一的硬件初始化接口
- 支持默认字体、HZFont、自定义字体配置
- LCD显示参数管理
- 触摸屏配置管理
- 字体渲染初始化
2.2 基础组件演示
- win_label.lua - 动态更新标签演示(实时时间显示,使用默认字体)
- win_button.lua - 基础按钮组件演示(使用默认字体)
- win_toggle_button.lua - 切换按钮演示(图标切换,使用默认字体)
- win_progress_bar.lua - 静态进度条演示(使用默认字体)
- win_dyn_progress_bar.lua - 动态进度条演示(自动往复动画,使用默认字体)
2.3 交互组件演示
- win_label.lua - 动态更新标签演示(实时时间显示,使用默认字体)
- win_button.lua - 基础按钮组件演示(使用默认字体)
- win_toggle_button.lua - 切换按钮演示(图标切换,使用默认字体)
- win_progress_bar.lua - 静态进度条演示(使用默认字体)
- win_dyn_progress_bar.lua - 动态进度条演示(自动往复动画,使用默认字体)
2.4 多媒体组件演示
- win_picture.lua - 静态图片显示演示(使用默认字体)
- win_autoplay_picture.lua - 自动轮播图片演示(使用默认字体)
2.5 高级功能演示
- win_all_component.lua - 所有组件综合演示(带滚动功能,使用默认字体)
- win_horizontal_slide.lua - 横向滑动页面演示(使用默认字体)
- win_vertical_slide.lua - 纵向滑动页面演示(使用默认字体)
- win_switch_page.lua - 页面切换演示(多页面导航,使用默认字体)
2.6 字体渲染演示
- win_hzfont.lua - 14 号固件内置矢量字体演示(HzFont)
三、准备硬件环境

1、Air8000核心板 × 1
2、AirLCD_1010 触摸配件板 × 1
3、母对母杜邦线 × 17,杜邦线太长的话,会出现 spi 通信不稳定的现象;
4、TYPE-C 数据线 × 1
5、Air8000核心板和 AirLCD_1010配件板的硬件接线方式为
- Air8000核心板通过 TYPE-C USB 口供电(核心板背面开关拨到 USB ON 一端 正面开关拨到 供电 一端),此种供电方式下,VDD_EXT 引脚和VBAT为 3.3V,可以直接给 AirLCD_1010配件板供电;
- 为了演示方便,所以 Air8000核心板上电后直接通过 VDD-EXT引脚给 AirLCD_1010配件板供电;
- 客户在设计实际项目时,一般来说,需要通过一个 GPIO 来控制 LDO 给配件板供电,这样可以灵活地控制配件板的供电,可以使项目的整体功耗降到最低;
LCD 显示屏接线
| Air8000核心板 | AirLCD_1010配件板 |
|---|---|
| LCD_CLK | SCLK/CLK |
| LCD_CS | CS |
| LCD_RST | RES/RST |
| LCD_SDA | SDA/MOS |
| LCD_RS | DC/RS |
| GPIO1 | BLK |
| VDD_EXT | VCC |
| I2C1_SCL | SCL |
| I2C1_SDA | SDA |
| WAKEUP0 | INT |
| GND | GND |
四、准备软件环境
4.1 软件环境
在开始实践本示例之前,先筹备一下软件环境:
1、烧录工具:Luatools 下载调试工具
2、内核固件:本demo开发测试时使用的固件为LuatOS-SoC_V2018_Air8000 1号固件,本demo对固件版本没有什么特殊要求,所以你如果要测试本demo时,可以直接使用最新版本的内核固件;如果发现最新版本的内核固件测试有问题,可以使用我们开发本demo时使用的内核固件版本来对比测试;
使用 HZfont 需要使用 V2020 版本以上的 14 号固件或114号固件,且 14 号固件或114号固件仅支持 HZfont
使用其他字体,demo 所使用的是 LuatOS-SoC_V2018 1 号固件
3、脚本文件:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8000/demo/ui/easyui/single
4、lib脚本文件:使用Luatools烧录时,勾选 添加默认lib 选项,使用默认lib脚本文件
准备好软件环境之后,接下来查看如何烧录项目文件到Air8000核心板,将本篇文章中演示使用的项目文件烧录到Air8000核心板中。
4.2 API 介绍
exeasyui UI扩展库:https://docs.openluat.com/osapi/ext/exeasyui/
五、程序结构
ui/easyui/single
│── main.lua
│── images
│── xxx.jpg
│── hw_font_drv.lua
│── win_all_component.lua
│── win_autoplay_picture.lua
│── win_button.lua
│── win_check_box.lua
│── win_combo_box.lua
│── win_dyn_progress_bar.lua
│── win_horizontal_slide.lua
│── win_input.lua
│── win_label.lua
│── win_message_box.lua
│── win_number_input.lua
│── win_password_input.lua
│── win_picture.lua
│── win_progress_bar.lua
│── win_switch_page.lua
│── win_toggle_button.lua
│── win_vertical_slide.lua
│── win_hzfont.lua
│── readme.md
5.1 文件说明
1、main.lua:整个项目的入口点。它负责初始化系统环境
2、images:
xxx.jpg:演示图片文件(和lua脚本文件一起烧录,会自动放置在/luadb/目录下)
3、hw_font_drv.lua:默认使用字体、lcd显示、tp触摸初始化驱动模块
4、win_all_component.lua:所有组件综合演示(带滚动功能,使用默认字体)
5、win_autoplay_picture.lua:自动轮播图片演示(使用默认字体)
6、win_button.lua:基础按钮组件演示(使用默认字体)
7、win_check_box.lua:复选框组件演示(使用默认字体)
8、win_combo_box.lua:下拉框组件演示(使用默认字体)
9、win_dyn_progress_bar.lua:动态进度条演示(自动往复动画,使用默认12号英文点阵字体)
10、win_horizontal_slide.lua:横向滑动页面演示(使用默认字体)
11、win_input.lua:文本输入框演示(使用默认字体)
12、win_label.lua:动态更新标签演示(实时时间显示,使用默认字体)
13、win_message_box.lua:消息框组件演示(使用默认字体)
14、win_number_input.lua:数字输入框演示(带增减按钮,使用默认字体)
15、win_password_input.lua:密码输入框演示(带显示/隐藏切换,使用默认字体)
16、win_picture.lua:静态图片显示演示(使用默认字体)
17、win_progress_bar.lua:静态进度条演示(使用默认字体)
18、win_switch_page.lua:页面切换演示(多页面导航,使用默认字体)
19、win_toggle_button.lua:切换按钮演示(图标切换,使用默认字体)
20、win_vertical_slide.lua:纵向滑动页面演示(使用默认字体)
21、win_hzfont.lua:14 号固件内置矢量字体演示(HzFont)
六、代码详解
6.1 main.lua
主程序文件 main.lua 是整个项目的入口点。它负责初始化系统环境。
6.2 hw_font_drv.lua
本文件为字体驱动配置模块,核心业务逻辑为:
1、配置LCD显示和触摸屏参数;
2、提供统一的硬件初始化接口;
local hw_font_drv = {}
-- 硬件配置参数
local hw_config = {
-- lcd_config参数填写可以参考合宙exlcd显示扩展库exlcd.init(param)接口说明:https://docs.openluat.com/osapi/ext/exlcd/#31-exlcdinitparam
lcd_config = {
lcd_model = "AirLCD_1010", -- LCD型号
-- pin_vcc = 24, -- 供电引脚,使用GPIO控制屏幕供电可配置
pin_rst = 36, -- 复位引脚
pin_pwr = 1, -- 背光控制引脚GPIO ID号
pin_pwm = 0, -- 背光控制引脚PWM ID号
port = lcd.HWID_0, -- 驱动端口
-- pin_dc = 0xFF, -- lcd数据/命令选择引脚GPIO ID号,使用lcd 专用 SPI 接口 lcd.HWID_0不需要填此参数,使用通用SPI接口需要赋值
direction = 0, -- lcd屏幕方向 0:0° 1:90° 2:180° 3:270°,屏幕方向和分辨率保存一致
w = 320, -- lcd 水平分辨率
h = 480, -- lcd 竖直分辨率
xoffset = 0, -- x偏移(不同屏幕ic 不同屏幕方向会有差异)
yoffset = 0, -- y偏移(不同屏幕ic 不同屏幕方向会有差异)
sleepcmd = 0X10, -- 睡眠命令,默认0X10
wakecmd = 0X11, -- 唤醒命令,默认0X11
-- bus_speed = 50*1000*1000, -- SPI总线速度,不填默认50M,若速率要求更高需要进行设置
-- interface_mode = lcd.WIRE_4_BIT_8_INTERFACE_I, -- lcd模式,默认lcd.WIRE_4_BIT_8_INTERFACE_I
-- direction0 = {0x36,0x00}, -- 0°方向的命令,(不同屏幕ic会有差异)
-- direction90 = {0x36,0x60}, -- 90°方向的命令,(不同屏幕ic会有差异)
-- direction180 ={0x36,0xc0} , -- 180°方向的命令,(不同屏幕ic会有差异)
-- direction270 = {0x36,0xA0}, -- 270°方向的命令,(不同屏幕ic会有差异)
-- hbp = nil, -- 水平后廊
-- hspw = nil, -- 水平同步脉冲宽度
-- hfp = 0, -- 水平前廊
-- vbp = 0, -- 垂直后廊
-- vspw = 0, -- 垂直同步脉冲宽度
-- vfp = 0, -- 垂直前廊
-- initcmd = nil, -- 自定义屏幕初始化命令表
-- flush_rate = nil, -- 刷新率
-- spi_dev = nil, -- spi设备,当port = "device"时有效,当port ≠ "device"时可不填或者填nil
-- init_in_service = false, -- 允许初始化在lcd service里运行,在后台初始化LCD,默认是false,Air8000/G/W/T/A、Air780EHM/EGH/EHV 支持填true,可加快初始化速度,默认SPI总线速度80M
},
-- tp_config参数填写可以参考合宙extp触摸扩展库以下三个接口说明:https://docs.openluat.com/osapi/ext/extp/#41-extpinitparam
-- 按extp.init(param)接口说明填写tp_model、i2c_id、pin_rst、pin_int参数
-- 按extp.set_publish_enabled(msg_type, enabled)接口说明和实际需求填写message_enabled{}列表内参数
-- 按extp.set_swipe_threshold(threshold)接口说明填写swipe_threshold和long_press_threshold参数
tp_config = {
tp_model = "AirLCD_1010", -- 触摸芯片/设备型号
i2c_id = 1, -- I2C总线ID
pin_rst = 0xFF, -- 触摸芯片复位引脚(AirLCD_1010上没有引出该引脚)
pin_int = gpio.WAKEUP0, -- 触摸芯片中断引脚
-- @param message_enabled 消息类型 ("ALL", "RAW_DATA", "TOUCH_DOWN", "MOVE_X", "MOVE_Y", "SWIPE_LEFT", "SWIPE_RIGHT", "SWIPE_UP", "SWIPE_DOWN", "SINGLE_TAP", "LONG_PRESS")
message_enabled = {
TOUCH_DOWN = true, -- 启用按下检测
MOVE_X = true, -- 启用横向滑动
MOVE_Y = true, -- 启用纵向滑动
SWIPE_LEFT = true, -- 启用左滑手势
SWIPE_RIGHT = true, -- 启用右滑手势
SWIPE_UP = true, -- 启用上滑手势
SWIPE_DOWN = true, -- 启用下滑手势
SINGLE_TAP = true, -- 启用点击手势
LONG_PRESS = false -- 禁用长按手势
},
swipe_threshold = 10, -- 设置滑动阈值
long_press_threshold = 2000 -- 设置长按阈值(毫秒)
}
}
function hw_font_drv.init(font_config)
-- 如果有字体配置,则添加到硬件配置中
if font_config then
hw_config.font_config = font_config
end
-- 初始化硬件
ui.hw_init(hw_config)
log.info("hw_font_drv", "硬件初始化完成", font_config and "使用字体配置" or "使用默认字体")
end
return hw_font_drv
6.3 win_all_component.lua
本文件为所有UI组件综合演示模块,核心业务逻辑为:
1、创建带滚动功能的窗口容器;
2、集成展示所有exEasyUI组件;
3、实现组件间的交互逻辑;
4、展示进度条、消息框、按钮、复选框、输入框等完整功能;
5、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器并启用滚动
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
page1:enable_scroll({
direction = "vertical",
content_height = 1000,
threshold = 8
})
-- ==================== 标题区域 ====================
local title = ui.label({
x = 100, y = 25,
text = "组件演示页面",
color = ui.COLOR_BLACK,
size = 16
})
page1:add(title)
-- ==================== 进度条组件区域 ====================
local progress_label = ui.label({
x = 20, y = 70,
text = "1. 进度条组件演示:",
color = ui.COLOR_BLACK,
size = 14
})
local progress = 0
local pb = ui.progress_bar({
x = 20, y = 100,
w = 200, h = 26,
progress = progress
})
local btn_progress = ui.button({
x = 230, y = 100,
w = 70, h = 26,
text = "+10%",
on_click = function(self)
progress = progress + 10
if progress > 100 then
progress = 0
end
pb:set_progress(progress)
pb:set_text("进度: " .. progress .. "%")
end
})
page1:add(progress_label)
page1:add(pb)
page1:add(btn_progress)
-- ==================== 消息框组件区域 ====================
local msgbox_label = ui.label({
x = 20, y = 140,
text = "2. 消息框组件演示:",
color = ui.COLOR_BLACK,
size = 14
})
local btn_msgbox = ui.button({
x = 20, y = 170,
w = 120, h = 30,
text = "弹出消息框",
on_click = function(self)
local message_box = ui.message_box({
x = 40, y = 150,
w = 240, h = 180,
wordWrap = true,
title = "祝福",
message = "愿你前路浩荡,未来可期.愿你保持热爱,奔赴山海。愿你所有的努力都不被辜负,最终活成自己最喜欢的模样.加油!",
buttons = { "接受祝福" }
})
ui.add(message_box)
end
})
page1:add(msgbox_label)
page1:add(btn_msgbox)
-- ==================== 切换按钮组件区域 ====================
local toggle_label = ui.label({
x = 20, y = 220,
text = "3. 切换按钮演示:",
color = ui.COLOR_BLACK,
size = 14
})
local btn_toggle = ui.button({
x = 20, y = 250,
w = 64, h = 64,
src = "/luadb/4.jpg",
src_toggled = "/luadb/5.jpg",
toggle = true,
})
page1:add(toggle_label)
page1:add(btn_toggle)
-- ==================== 复选框组件区域 ====================
local checkbox_label = ui.label({
x = 20, y = 330,
text = "4. 复选框组件演示:",
color = ui.COLOR_BLACK,
size = 14
})
local checkbox1 = ui.check_box({
x = 20, y = 360,
text = "选项A",
checked = false,
on_change = function(checked)
log.info("checkbox", "选项A:", checked)
end
})
local checkbox2 = ui.check_box({
x = 120, y = 360,
text = "选项B",
checked = true,
on_change = function(checked)
log.info("checkbox", "选项B:", checked)
end
})
page1:add(checkbox_label)
page1:add(checkbox1)
page1:add(checkbox2)
-- ==================== 输入框组件区域 ====================
local input_label = ui.label({
x = 20, y = 410,
text = "5. 输入框组件演示:",
color = ui.COLOR_BLACK,
size = 14
})
local text_input = ui.input({
x = 20, y = 440,
w = 200, h = 30,
placeholder = "请输入文本...",
max_length = 20
})
page1:add(input_label)
page1:add(text_input)
-- ==================== 密码输入框组件区域 ====================
local password_label = ui.label({
x = 20, y = 490,
text = "6. 密码输入框演示:",
color = ui.COLOR_BLACK,
size = 14
})
local password_input = ui.input({
x = 20, y = 520,
w = 150, h = 30,
placeholder = "请输入密码...",
input_type = "password",
max_length = 16
})
local password_visible = false
local btn_password_toggle = ui.button({
x = 180, y = 520,
w = 60, h = 30,
text = "显示",
bg_color = ui.COLOR_BLUE,
text_color = ui.COLOR_WHITE,
on_click = function()
password_visible = not password_visible
password_input.input_type = password_visible and "text" or "password"
btn_password_toggle:set_text(password_visible and "隐藏" or "显示")
end
})
page1:add(password_label)
page1:add(password_input)
page1:add(btn_password_toggle)
-- ==================== 数字输入框组件区域 ====================
local number_label = ui.label({
x = 20, y = 570,
text = "7. 数字输入框演示:",
color = ui.COLOR_BLACK,
size = 14
})
local number_input = ui.input({
x = 20, y = 600,
w = 100, h = 30,
placeholder = "0-100",
input_type = "number",
max_length = 3
})
local btn_number_minus = ui.button({
x = 130, y = 600,
w = 40, h = 30,
text = "-",
on_click = function()
local value = tonumber(number_input:get_text()) or 0
if value > 0 then
number_input:set_text(tostring(value - 1))
end
end
})
local btn_number_plus = ui.button({
x = 180, y = 600,
w = 40, h = 30,
text = "+",
on_click = function()
local value = tonumber(number_input:get_text()) or 0
if value < 100 then
number_input:set_text(tostring(value + 1))
end
end
})
page1:add(number_label)
page1:add(number_input)
page1:add(btn_number_minus)
page1:add(btn_number_plus)
-- ==================== 下拉框组件区域 ====================
local combo_label = ui.label({
x = 20, y = 650,
text = "8. 下拉框组件演示:",
color = ui.COLOR_BLACK,
size = 14
})
local combo_box = ui.combo_box({
x = 20, y = 680,
w = 200, h = 30,
options = { "选项1", "选项2", "选项3" },
placeholder = "请选择",
selected = 1,
on_select = function(value, index, text)
log.info("combo_box", "选择了:", text, "索引:", index)
end
})
page1:add(combo_label)
page1:add(combo_box)
-- ==================== 图片轮播组件区域 ====================
local picture_label = ui.label({
x = 20, y = 730,
text = "9. 图片自动轮播组件演示:",
color = ui.COLOR_BLACK,
size = 14
})
local pic = ui.picture({
x = 20, y = 760,
w = 128, h = 128,
sources = { "/luadb/1.jpg", "/luadb/2.jpg", "/luadb/3.jpg" },
autoplay = true,
interval = 1500
})
local btn_picture_toggle = ui.button({
x = 160, y = 760,
w = 80, h = 30,
text = "手动切换图片",
on_click = function()
pic:next()
end
})
page1:add(picture_label)
page1:add(pic)
page1:add(btn_picture_toggle)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.4 win_autoplay_picture.lua
本文件为自动轮播图片演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加图片轮播组件;
3、配置自动播放和切换间隔;
4、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建自动轮播图片组件
local pic = ui.picture({
x = 20, y = 20,
sources = {"/luadb/1.jpg", "/luadb/2.jpg", "/luadb/3.jpg"},
autoplay = true,
interval = 1500
})
-- 添加组件到窗口
page1:add(pic)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.5 win_button.lua
本文件为基础按钮组件演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加基础按钮组件;
3、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建按钮组件(文本模式)
local btn1 = ui.button({ x = 20, y = 20, text = "基础按钮" })
-- 添加组件到窗口
page1:add(btn1)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.6 win_check_box.lua
本文件为复选框组件演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加复选框组件;
3、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建复选框组件
local cb = ui.check_box({
x = 20, y = 20,
text = "Check me"
})
-- 添加组件到窗口
page1:add(cb)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.7 win_combo_box.lua
本文件为下拉框组件演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加下拉框组件;
3、配置选项列表和选择回调;
4、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建下拉框组件
local combo_box = ui.combo_box({
x = 20, y = 20,
w = 200, h = 30,
options = { "选项1", "选项2", "选项3" },
placeholder = "请选择",
selected = 1,
on_select = function(value, index, text)
log.info("component_page", "选择了:", text, "索引:", index)
end
})
-- 添加组件到窗口
page1:add(combo_box)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.8 win_dyn_progress_bar.lua
本文件为动态进度条演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加进度条组件;
3、在主循环中动态更新进度条数值;
4、实现进度条往复动画效果;
5、启动UI渲染循环持续刷新显示;
local direction = 1
local current = 0
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建进度条组件
local pb = ui.progress_bar({
x = 20, y = 20,
w = 280, h = 26
})
-- 添加组件到窗口
page1:add(pb)
-- 注册窗口到UI系统
ui.add(page1)
-- 启动exeasyui刷新主循环
while true do
-- 动态更新进度条数值
current = current + direction
if current >= 100 then
direction = -1
elseif current <= 0 then
direction = 1
end
pb:set_progress(current)
-- 等待30ms
sys.wait(30)
end
end
sys.taskInit(ui_main)
6.9 win_horizontal_slide.lua
本文件为横向滑动页面演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、启用横向滑动功能;
3、创建两页内容并水平排列;
4、实现横向滑动切换页面效果;
5、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local win = ui.window({ background_color = ui.COLOR_WHITE })
-- 启用横向滚动,将两页内容并排布置
local page_w, page_h = lcd.getSize()
local totalW = page_w * 2
-- 创建横向滑动窗口
win:enable_scroll({
direction = "horizontal",
content_width = totalW,
threshold = 8,
page_width = page_w
})
-- 创建网格按钮函数
local function makeGrid(offset_x, label_prefix)
local cols, rows = 3, 3
local bw, bh = 90, 80
local mx, my = 20 + offset_x, 60
local gapx, gapy = 10, 10
local n = 1
for r = 0, rows - 1 do
for c = 0, cols - 1 do
local x = mx + c * (bw + gapx)
local y = my + r * (bh + gapy)
local btn = ui.button({
x = x,
y = y,
w = bw,
h = bh,
text = string.format("%s-%d", label_prefix, n)
})
win:add(btn)
n = n + 1
end
end
end
-- 创建左页和右页内容
makeGrid(0, "P1") -- 第一页
makeGrid(page_w, "P2") -- 第二页
-- 注册窗口到UI系统
ui.add(win)
end
sys.taskInit(ui_main)
6.10 win_input.lua
本文件为文本输入框演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加文本输入框组件;
3、设置占位符文本和最大长度限制;
4、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建文本输入框组件
local text_input = ui.input({
x = 20, y = 20,
w = 200, h = 30,
placeholder = "请输入文本...",
max_length = 20
})
-- 添加组件到窗口
page1:add(text_input)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.11 win_label.lua
本文件为基础标签组件演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加静态标签组件显示"hello exEasyUI"文本;
3、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建标签组件
local lbl = ui.label({ x = 20, y = 20, text = "hello exEasyUI"})
-- 添加组件到窗口
page1:add(lbl)
-- 注册窗口到UI系统
ui.add(page1)
-- 循环刷新时间
while true do
-- 更新时间给文本组件lbl
lbl:set_text("时间:"..os.date("%Y-%m-%d %H:%M:%S"))
-- 等待300ms
sys.wait(300)
end
end
sys.taskInit(ui_main)
6.12 win_message_box.lua
本文件为消息框组件演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加消息框组件显示通知信息;
3、启用自动换行功能显示长文本;
4、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建消息框组件
local box = ui.message_box({
x = 20, y = 20,
wordWrap = true,
title = "通知",
message = "愿你前路浩荡,未来可期.愿你保持热爱,奔赴山海。愿你所有的努力都不被辜负,最终活成自己最喜欢的模样.加油!"
})
-- 添加组件到窗口
page1:add(box)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.13 win_number_input.lua
本文件为数字输入框演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加数字输入框组件;
3、添加增减按钮控制数字输入;
4、实现数字范围限制功能;
5、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建数字输入框组件
local number_input = ui.input({
x = 20, y = 20,
w = 100, h = 30,
placeholder = "0-100",
input_type = "number",
max_length = 3
})
-- 创建减少按钮
local btn_number_minus = ui.button({
x = 130, y = 20,
w = 40, h = 30,
text = "-",
on_click = function()
local value = tonumber(number_input:get_text()) or 0
if value > 0 then
number_input:set_text(tostring(value - 1))
end
end
})
-- 创建增加按钮
local btn_number_plus = ui.button({
x = 180, y = 20,
w = 40, h = 30,
text = "+",
on_click = function()
local value = tonumber(number_input:get_text()) or 0
if value < 100 then
number_input:set_text(tostring(value + 1))
end
end
})
-- 添加组件到窗口
page1:add(number_input)
page1:add(btn_number_minus)
page1:add(btn_number_plus)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.14 win_password_input.lua
本文件为密码输入框演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加密码输入框组件;
3、添加显示/隐藏密码切换按钮;
4、实现密码可见性切换功能;
5、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建密码输入框组件
local password_input = ui.input({
x = 20, y = 20,
w = 150, h = 30,
placeholder = "请输入密码...",
input_type = "password",
max_length = 16
})
-- 创建密码显示/隐藏切换按钮
local password_visible = false
local btn_password_toggle = ui.button({
x = 180, y = 20,
w = 60, h = 30,
text = "显示",
bg_color = ui.COLOR_BLUE,
text_color = ui.COLOR_WHITE,
on_click = function()
password_visible = not password_visible
password_input.input_type = password_visible and "text" or "password"
btn_password_toggle:set_text(password_visible and "隐藏" or "显示")
end
})
-- 添加组件到窗口
page1:add(password_input)
page1:add(btn_password_toggle)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.15 win_picture.lua
本文件为静态图片显示演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加静态图片显示组件;
3、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建静态图片组件
local pic = ui.picture({
x = 20, y = 20,
sources = {"/luadb/logo.jpg"}
})
-- 添加组件到窗口
page1:add(pic)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.16 win_progress_bar.lua
本文件为静态进度条演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加静态进度条组件;
3、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建进度条组件
local pb = ui.progress_bar({
x = 20, y = 20,
w = 280, h = 26
})
-- 添加组件到窗口
page1:add(pb)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.17 win_switch_page.lua
本文件为页面切换演示模块,核心业务逻辑为:
1、创建主页面窗口容器;
2、配置多个子页面工厂函数;
3、实现页面间切换导航功能;
4、演示消息框页面和复选框页面;
5、实现子页面销毁和内存管理;
6、启动UI渲染循环持续刷新显示;
-- 创建消息框演示页面
local function msgbox_page()
local win = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建页面标题(使用无按钮的消息框)
local title = ui.message_box({
x = 10, y = 10,
w = 300, h = 80,
title = "消息框页面",
message = "点击按钮弹出消息框",
buttons = {} -- 空按钮数组,不显示按钮
})
-- 创建"弹出消息框"按钮
local btn = ui.button({
x = 20, y = 140,
w = 180, h = 50,
text = "弹出消息框",
on_click = function()
-- 创建消息框
local box = ui.message_box({
x = 40, y = 210,
w = 240, h = 120,
title = "提示",
message = "这是一条消息",
buttons = { "确定", "取消" },
on_result = function()
-- 处理按钮点击逻辑
end
})
ui.add(box)
end
})
-- 创建"返回"按钮
local back = ui.button({
x = 220, y = 140,
w = 80, h = 50,
text = "返回",
on_click = function()
win:back() -- 返回主页
end
})
-- 添加组件到窗口
win:add(title)
win:add(btn)
win:add(back)
return win
end
-- 创建复选框演示页面
local function check_box_page()
local win = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建页面标题
local title = ui.message_box({
x = 10, y = 10,
w = 300, h = 80,
title = "复选框页面",
message = "演示多个check_box",
buttons = {}
})
-- 创建三个复选框
local cb1 = ui.check_box({ x = 20, y = 120, text = "选项A" })
local cb2 = ui.check_box({ x = 20, y = 160, text = "选项B", checked = true })
local cb3 = ui.check_box({ x = 20, y = 200, text = "选项C" })
-- 创建返回按钮
local back = ui.button({
x = 20, y = 260,
w = 120, h = 40,
text = "返回主页",
on_click = function()
win:back()
end
})
-- 添加组件到窗口
win:add(title)
win:add(cb1)
win:add(cb2)
win:add(cb3)
win:add(back)
return win
end
-- 主程序入口函数
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建主页面
local home = ui.window({ background_color = ui.COLOR_WHITE })
-- 配置子页面工厂函数
home:configure_subpages({
page1 = msgbox_page, -- 消息框演示页面
page2 = check_box_page -- 复选框演示页面
})
-- 创建导航按钮1:进入复选框示例页面
local btn1 = ui.button({
x = 20, y = 60,
w = 280, h = 50,
text = "复选框示例",
on_click = function()
home:show_subpage("page2")
end
})
-- 创建导航按钮2:进入消息框示例页面
local btn2 = ui.button({
x = 20, y = 130,
w = 280, h = 50,
text = "消息框示例",
on_click = function()
home:show_subpage("page1")
end
})
-- 创建功能按钮:移除复选框子界面(演示销毁功能)
local btnRemove = ui.button({
x = 20, y = 200,
w = 280, h = 50,
text = "移除复选框子界面(销毁)",
on_click = function()
-- 强制销毁缓存的check_box子页面,释放内存
home:close_subpage("page2", { destroy = true })
end
})
-- 添加按钮到主页面
home:add(btn1)
home:add(btn2)
home:add(btnRemove)
-- 注册主页面到UI系统
ui.add(home)
end
sys.taskInit(ui_main)
6.18 win_toggle_button.lua
本文件为切换按钮演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、添加图标模式切换按钮组件;
3、实现按钮点击切换图片功能;
4、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local page1 = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建切换按钮组件(图标模式)
local btn2 = ui.button({
x = 20, y = 20,
w = 64, h = 64,
toggle = true, -- 启用切换模式
src = "/luadb/4.jpg", -- 默认图片
src_toggled = "/luadb/5.jpg", -- 切换状态时的图片
})
-- 添加组件到窗口
page1:add(btn2)
-- 注册窗口到UI系统
ui.add(page1)
end
sys.taskInit(ui_main)
6.19 win_vertical_slide.lua
本文件为纵向滑动页面演示模块,核心业务逻辑为:
1、创建窗口容器并设置白色背景;
2、启用纵向滑动功能;
3、创建两页内容并垂直排列;
4、实现纵向滑动切换页面效果;
5、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 显示触摸初始化
hw_font_drv.init()
-- 设置主题
ui.sw_init({ theme = "light" })
-- 创建窗口容器
local win = ui.window({ background_color = ui.COLOR_WHITE })
-- 启用纵向分页滚动,将两页内容上下排布
local page_w, page_h = lcd.getSize()
local total_h = page_h * 2
-- 创建纵向滑动窗口
win:enable_scroll({
direction = "vertical",
content_height = total_h,
threshold = 10,
page_height = page_h
})
-- 创建按钮布局函数
local function makebuttons(offset_y, label_prefix)
-- 竖直等间距排列:1列3行,水平居中
local cols, rows = 1, 3
local bw, bh = 90, 80
local mx = math.floor((page_w - bw) / 2) -- 居中
local gap = math.floor((page_h - rows * bh) / (rows + 1))
if gap < 8 then gap = 8 end
local n = 1
for r = 0, rows - 1 do
local x = mx
local y = offset_y + gap + r * (bh + gap)
local btn = ui.button({
x = x, y = y,
w = bw, h = bh,
text = string.format("%s-%d", label_prefix, n)
})
win:add(btn)
n = n + 1
end
end
-- 创建上页和下页内容
makebuttons(0, "P1") -- 第一页
makebuttons(page_h, "P2") -- 第二页
-- 注册窗口到UI系统
ui.add(win)
end
sys.taskInit(ui_main)
6.20 win_hzfont.lua
本文件为HzFont矢量字体演示模块,核心业务逻辑为:
1、启用14号固件内置HzFont矢量字体方式驱动;
2、创建窗口容器并设置白色背景;
3、添加多个标签组件展示矢量字体特性;
4、演示抗锯齿渲染和智能缓存功能;
5、启动UI渲染循环持续刷新显示;
local function ui_main()
-- 启用14号固件内置HzFont矢量字体方式驱动
hw_font_drv.init({
type = "hzfont",
size = 32,
antialias = -1 -- 自动抗锯齿
})
-- 设置主题
ui.init({ theme = "light" })
-- 创建窗口容器
local win = ui.window({ background_color = ui.COLOR_WHITE })
-- 创建多个标签展示矢量字体特性
local text1 = ui.label({ x = 10, y = 20, text = "HzFont矢量字体", color = ui.COLOR_BLACK })
local text2 = ui.label({ x = 10, y = 60, text = "Hello World", color = ui.COLOR_RED })
local text3 = ui.label({ x = 10, y = 100, text = "支持10-100号大小", color = ui.COLOR_GREEN })
local text4 = ui.label({ x = 10, y = 140, text = "支持抗锯齿渲染", color = ui.COLOR_BLUE })
local text5 = ui.label({ x = 10, y = 180, text = "智能缓存加速", color = ui.COLOR_ORANGE })
-- 添加组件到窗口
win:add(text1)
win:add(text2)
win:add(text3)
win:add(text4)
win:add(text5)
-- 注册窗口到UI系统
ui.add(win)
end
sys.taskInit(ui_main)
七、显示效果展示
7.1 硬件准备
- 按照硬件接线表连接所有设备
- 通过 TYPE-C USB 口供电
- 检查所有接线无误
7.2 软件配置
在 main.lua 中选择要运行的演示模块:
-- 必须加载才能启用exeasyui的功能
ui = require("exeasyui")
-- 加载显示、触摸和字体驱动模块
hw_font_drv = require("hw_font_drv")
-- 引入演示模块
-- 使用哪个加载哪个,每次选择加载一个;
-- require("win_label") --动态更新标签演示
-- require("win_button") --基础按钮组件演示
-- require("win_toggle_button") --切换按钮演示
-- require("win_progress_bar") --静态进度条演示
-- require("win_dyn_progress_bar") --动态进度条演示
-- require("win_message_box") --消息框组件演示
-- require("win_check_box") --复选框组件演示
-- require("win_picture") --静态图片显示演示
-- require("win_autoplay_picture") --自动轮播图片演示
-- require("win_combo_box") --下拉框组件演示
-- require("win_input") --文本输入框演示
-- require("win_password_input") --密码输入框演示
-- require("win_number_input") --数字输入框演示
require("win_all_component") --所有组件综合演示
-- require("win_horizontal_slide") --横向滑动页面演示
-- require("win_vertical_slide") --纵向滑动页面演示
-- require("win_switch_page") --页面切换演示
-- require("win_hzfont") --内置软件矢量字体演示
7.3 软件烧录
- 使用 Luatools 烧录对应型号的最新内核固件
- 下载本项目所有脚本文件和图片文件
- 将演示图片文件(如
1.jpg、2.jpg等)同.lua脚本文件一起烧录到脚本分区 - 设备自动重启后开始运行选定的演示模块
7.4 功能测试
所有组件综合演示(带滚动功能,使用默认字体)


7.5 预期效果
- 响应式设计:所有组件支持触摸交互
- 主题支持:支持浅色/深色主题切换
- 滚动功能:支持横向和纵向滚动页面
- 动态更新:支持实时数据更新显示
- 事件处理:完整的触摸和点击事件处理
八、使用合宙 LuatOS-PC 模拟器仿真 exeasyui
8.1 PC 模拟器说明
- 合宙 LuatOS-PC 模拟器是一个能在 win10/win11 上模拟运行 lua 脚本的仿真软件,内置 LuatOS 内核固件,运行.lua 脚本效果与实际设备类似;
- 目前 PC 模拟器可以通过 LuaTools 工具的资源管理器进行下载,所以我们需要先下载安装 LuaTools 工具,然后再通过 LuaTools 工具来下载 LuatOS-PC 模拟器,最后通过 LuatOS-PC 模拟器运行 exeasyui 演示 demo;
8.2 LuatOS-PC 模拟器安装步骤
1、点击下载:Luatools v3 下载调试工具
2、通过 LuaTools 工具下载 LuatOS-PC 模拟器
- LuaTools 工具安装完毕后,点击首页面左上角的--账户--打开资源下载
- 选择-公共资源--LuatOS 的 PC 模拟器--选择最新版本 LuatOS-PC 模拟器--点击开始下载(非刷机)
- (这里以Air780EHM为例,实际选择Air8000最新的固件)


8.3 下载底层固件和上层运行脚本
- 下载运行所需固件,点击资源管理--选择 Air8000 的 LuatOS 固件--下载最新版本的 1 号固件和 14 号固件
- 下载本演示 demo 内所有.lua 脚本文件、images 文件夹内的图片

8.4 使用 LuatOS-PC 模拟器仿真 运行 exeasyui 演示 demo
1、返回 Luatloos 工具首页,点击--项目管理测试

2、创建一个项目并命名

3、选择固件刚才下载的固件--点击打开,路径在 Luatools 目录下 resource\LuatOS_Air8000\LuatOS-SoC_VXXXX_Air8000

4、将下载的 demo 图片资源和.lua文件拖入到项目管理内的脚本和资源列表区域--勾选添加默认 lib--点击模拟器运行--出来的界面就是 demo 在实际设备上运行界面的仿真,可以用鼠标进行交互


5、如需切换 demo 内的演示内容,可打开下载脚本文件中的 mian.lua 文件,将需要演示 demo 的 require 前面--去掉,将不需要演示 demo 的 require 前面加上--。注释掉 require 的其他 demo 文件后,再点击模拟器运行,就会出现所 require 的 demo 对应的界面仿真。
- 比如:需要演示下拉框组件,将-- require("win_combo_box") 改为 require("win_combo_box") ,并把其他加载的组件改为注释状态。

九、常见问题
1、显示异常
- 检查 LCD 接线是否存在异常
- 确认 hw_font_drv.lua 内屏幕型号及其参数配置是否正确
2、触摸无响应
- 检查 I2C 接线是否存在异常
- 确认确认 hw_font_drv.lua 内触摸芯片型号配置正确
3、字体显示异常
- 确认选择的字体驱动与硬件匹配
- 检查固件版本是否支持所选字体
4、图片无法显示
- 确认图片文件已正确烧录
- 检查文件路径和名称是否正确
5、系统运行缓慢
- 检查是否有过多的组件同时渲染
- 适当调整刷新间隔时间
6、 调试技巧
- 使用
log.info()输出调试信息 - 检查系统内存使用情况
- 逐步启用组件排查问题