跳转至

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/Air780EHM_Air780EHV_Air780EGH/demo/ui/airui/single

二、演示功能概述

2.1 系统核心模块

1、main.lua - 主程序入口模块

  • 项目初始化和版本定义
  • 系统任务调度和管理
  • 看门狗配置和系统监控
  • 演示模块的选择和加载
  • 提供统一的程序启动入口

2、ui_main.lua - 用户界面主控模块

  • 多页面管理和切换逻辑
  • 触摸事件分发和处理
  • 界面渲染调度
  • 主题管理和配置
  • 提供完整的用户交互体验

3、hw_font_drv.lua - lcd显示、tp触摸初始化驱动模块

  • 统一的硬件初始化接口
  • LCD显示参数管理
  • 触摸屏配置管理

2.2 基础组件演示

1、win_label.lua - 动态更新标签演示(实时时间显示,使用默认12号英文点阵字体)

2、win_button.lua - 基础按钮组件演示(使用默认12号英文点阵字体)

3、win_toggle_button.lua - 切换按钮演示(图标切换,使用默认12号英文点阵字体)

4、win_progress_bar.lua - 静态进度条演示(使用默认12号英文点阵字体)

5、win_dyn_progress_bar.lua - 动态进度条演示(自动往复动画,使用默认12号英文点阵字体)

2.3 交互组件演示

1、win_message_box.lua - 消息框组件演示(使用默认12号英文点阵字体)

2、win_check_box.lua - 复选框组件演示(使用默认12号英文点阵字体)

3、win_combo_box.lua - 下拉框组件演示(使用默认12号英文点阵字体)

4、win_input.lua - 文本输入框演示(使用默认12号英文点阵字体)

5、win_password_input.lua - 密码输入框演示(带显示/隐藏切换,使用默认12号英文点阵字体)

6、win_number_input.lua - 数字输入框演示(带增减按钮,使用默认12号英文点阵字体)

2.4 多媒体组件演示

1、win_picture.lua - 静态图片显示演示(使用默认12号英文点阵字体)

2、win_autoplay_picture.lua - 自动轮播图片演示(使用默认12号英文点阵字体)

2.5 高级功能演示

1、win_all_component.lua - 所有组件综合演示(带滚动功能,使用默认12号英文点阵字体)

2、win_horizontal_slide.lua - 横向滑动页面演示(使用默认12号英文点阵字体)

3、win_vertical_slide.lua - 纵向滑动页面演示(使用默认12号英文点阵字体)

4、win_switch_page.lua - 页面切换演示(多页面导航,使用默认12号英文点阵字体)

三、准备硬件环境

1、Air780EPM 核心板 × 1

2、AirLCD_1010 触摸配件板 × 1

3、母对母杜邦线 × 11,杜邦线太长的话,会出现 spi 通信不稳定的现象;

4、TYPE-C 数据线 × 1

5、Air780EPM 核心板和 AirLCD_1010 配件板的硬件接线方式为

  • Air780EPM 核心板通过 TYPE-C USB 口供电(核心板正面开关拨到 ON 一端),此种供电方式下,VBAT 引脚为 3.3V,可以直接给 AirLCD_1010 配件板供电;
  • 为了演示方便,所以 Air780EPM 核心板上电后直接通过 VBAT 引脚给 AirLCD_1010 配件板供电;
  • 客户在设计实际项目时,一般来说,需要通过一个 GPIO 来控制 LDO 给配件板供电,这样可以灵活地控制配件板的供电,可以使项目的整体功耗降到最低;

LCD 显示屏接线

Air780EPM 核心板 AirLCD_1010配件板
53/LCD_CLK SCLK/CLK
52/LCD_CS CS
49/LCD_RST RES/RST
50/LCD_SDA SDA/MOS
51/LCD_RS DC/RS
22/GPIO1 BLK
VBAT VCC
67/I2C1_SCL SCL
66/I2C1_SDA SDA
19/GPIO22 INT

四、准备软件环境

4.1 软件环境

在开始实践本示例之前,先筹备一下软件环境:

1、烧录工具:Luatools 下载调试工具

2、本demo开发测试时使用的固件为LuatOS-SoC_V2018_Air780EPM 1号固件,本demo对固件版本没有什么特殊要求,所以你如果要测试本demo时,可以直接使用最新版本的内核固件Air780EPM固件Air780EHM固件;如果发现最新版本的内核固件测试有问题,可以使用我们开发本demo时使用的内核固件版本来对比测试;

3、脚本文件:

Air780EPM脚本文件:https://gitee.com/openLuat/LuatOS/tree/master/module/Air780EPM/demo/ui/easyui/single

Air780EHM脚本文件:https://gitee.com/openLuat/LuatOS/tree/master/module/Air780EHM_Air780EHV_Air780EGH/demo/ui/easyui/single

4、lib脚本文件:使用Luatools烧录时,勾选 添加默认lib 选项,使用默认lib脚本文件

准备好软件环境之后,接下来查看如何烧录项目文件到Air780EPM核心板,将本篇文章中演示使用的项目文件烧录到Air780EPM/Air780EHM核心板中。

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
│── 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:所有组件综合演示(带滚动功能,使用默认12号英文点阵字体)

5、win_autoplay_picture.lua:自动轮播图片演示(使用默认12号英文点阵字体)

6、win_button.lua:基础按钮组件演示(使用默认12号英文点阵字体)

7、win_check_box.lua:复选框组件演示(使用默认12号英文点阵字体)

8、win_combo_box.lua:下拉框组件演示(使用默认12号英文点阵字体)

9、win_dyn_progress_bar.lua:动态进度条演示(自动往复动画,使用默认12号英文点阵字体)

10、win_horizontal_slide.lua:横向滑动页面演示(使用默认12号英文点阵字体)

11、win_input.lua:文本输入框演示(使用默认12号英文点阵字体)

12、win_label.lua:动态更新标签演示(实时时间显示,使用默认12号英文点阵字体)

13、win_message_box.lua:消息框组件演示(使用默认12号英文点阵字体)

14、win_number_input.lua:数字输入框演示(带增减按钮,使用默认12号英文点阵字体)

15、win_password_input.lua:密码输入框演示(带显示/隐藏切换,使用默认12号英文点阵字体)

16、win_picture.lua:静态图片显示演示(使用默认12号英文点阵字体)

17、win_progress_bar.lua:静态进度条演示(使用默认12号英文点阵字体)

18、win_switch_page.lua:页面切换演示(多页面导航,使用默认12号英文点阵字体)

19、win_toggle_button.lua:切换按钮演示(图标切换,使用默认12号英文点阵字体)

20、win_vertical_slide.lua:纵向滑动页面演示(使用默认12号英文点阵字体)

六、代码详解

6.1 main.lua

主程序文件 main.lua 是整个项目的入口点。它负责初始化系统环境。

6.2 hw_font_drv.lua

本文件为字体驱动配置模块,核心业务逻辑为:

1、提供统一的硬件初始化接口;

2、默认使用内置12号英文点阵字体;

3、配置LCD显示和触摸屏参数;

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 = 22,             -- 触摸芯片中断引脚
        -- @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 = "Component Demo Page",
        color = ui.COLOR_BLACK,
        size = 12
    })
    page1:add(title)

    -- ==================== 进度条组件区域 ====================
    local progress_label = ui.label({
        x = 20,
        y = 70,
        text = "1. Progress Bar Demo:",
        color = ui.COLOR_BLACK,
        size = 12
    })

    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: " .. progress .. "%")
        end
    })

    page1:add(progress_label)
    page1:add(pb)
    page1:add(btn_progress)

    -- ==================== 消息框组件区域 ====================
    local msgbox_label = ui.label({
        x = 20,
        y = 140,
        text = "2. Message Box Demo:",
        color = ui.COLOR_BLACK,
        size = 12
    })

    local btn_msgbox = ui.button({
        x = 20,
        y = 170,
        w = 150,
        h = 30,
        text = "Show Message Box",
        on_click = function(self)
            local message_box = ui.message_box({
                x = 30,
                y = 150,
                w = 260,
                h = 180,
                wordWrap = true,
                title = "Greeting",
                message =
                "May your journey be smooth and your future bright. Keep your passion and explore the world. May all your efforts be rewarded and you become the person you want to be. Good luck!",
                buttons = { "Accept" }
            })
            ui.add(message_box)
        end
    })

    page1:add(msgbox_label)
    page1:add(btn_msgbox)

    -- ==================== 切换按钮组件区域 ====================
    local toggle_label = ui.label({
        x = 20,
        y = 220,
        text = "3. Toggle Button Demo:",
        color = ui.COLOR_BLACK,
        size = 12
    })

    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. Check Box Demo:",
        color = ui.COLOR_BLACK,
        size = 12
    })

    local checkbox1 = ui.check_box({
        x = 20,
        y = 360,
        text = "Option A",
        checked = false,
        on_change = function(checked)
            log.info("checkbox", "Option A:", checked)
        end
    })

    local checkbox2 = ui.check_box({
        x = 120,
        y = 360,
        text = "Option B",
        checked = true,
        on_change = function(checked)
            log.info("checkbox", "Option B:", checked)
        end
    })

    page1:add(checkbox_label)
    page1:add(checkbox1)
    page1:add(checkbox2)

    -- ==================== 输入框组件区域 ====================
    local input_label = ui.label({
        x = 20,
        y = 410,
        text = "5. Input Box Demo:",
        color = ui.COLOR_BLACK,
        size = 12
    })

    local text_input = ui.input({
        x = 20,
        y = 440,
        w = 200,
        h = 30,
        placeholder = "Enter text...",
        max_length = 20
    })

    page1:add(input_label)
    page1:add(text_input)

    -- ==================== 密码输入框组件区域 ====================
    local password_label = ui.label({
        x = 20,
        y = 490,
        text = "6. Password Input Demo:",
        color = ui.COLOR_BLACK,
        size = 12
    })

    local password_input = ui.input({
        x = 20,
        y = 520,
        w = 150,
        h = 30,
        placeholder = "Enter password...",
        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 = "Show",
        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 "Hide" or "Show")
        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. Number Input Demo:",
        color = ui.COLOR_BLACK,
        size = 12
    })

    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. Combo Box Demo:",
        color = ui.COLOR_BLACK,
        size = 12
    })

    local combo_box = ui.combo_box({
        x = 20,
        y = 680,
        w = 200,
        h = 30,
        options = { "Option 1", "Option 2", "Option 3" },
        placeholder = "Please select",
        selected = 1,
        on_select = function(value, index, text)
            log.info("combo_box", "Selected:", text, "Index:", index)
        end
    })

    page1:add(combo_label)
    page1:add(combo_box)

    -- ==================== 图片轮播组件区域 ====================
    local picture_label = ui.label({
        x = 20,
        y = 730,
        text = "9. Picture Carousel Demo:",
        color = ui.COLOR_BLACK,
        size = 12
    })

    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 = 120,
        h = 30,
        text = "Manual Switch",
        on_click = function()
            pic:next()
        end
    })

    page1:add(picture_label)
    page1:add(pic)
    page1:add(btn_picture_toggle)

    -- 注册窗口到UI系统
    ui.add(page1)

    -- 启动exeasyui刷新主循环
    while true do
        ui.refresh()
        sys.wait(30) -- 约33FPS刷新率
    end
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)

    -- 启动exeasyui刷新主循环
    while true do
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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 = "Button" })

    -- 添加组件到窗口
    page1:add(btn1)

    -- 注册窗口到UI系统
    ui.add(page1)

    -- 启动exeasyui刷新主循环
    while true do      
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30) 
    end
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)

    -- 启动exeasyui刷新主循环
    while true do
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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 = { "Option 1", "Option 2", "Option 3" },
        placeholder = "Please select",
        selected = 1,
        on_select = function(value, index, text)
            log.info("component_page", "Selected:", text, "Index:", index)
        end
    })

    -- 添加组件到窗口
    page1:add(combo_box)

    -- 注册窗口到UI系统
    ui.add(page1)

    -- 启动exeasyui刷新主循环
    while true do
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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)

        -- 刷新显示
        ui.refresh()
        -- 等待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()

    log.info("h", page_h, "w", page_w)
    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)

    -- 启动exeasyui刷新主循环
    while true do
        ui.refresh()
        sys.wait(30)
    end
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 = "Enter text...",
        max_length = 20
    })

    -- 添加组件到窗口
    page1:add(text_input)

    -- 注册窗口到UI系统
    ui.add(page1)

    -- 启动exeasyui刷新主循环
    while true do
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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)

    -- 启动exeasyui刷新主循环
    while true do
        -- 更新时间给文本组件lbl
        lbl:set_text("时间:"..os.date("%Y-%m-%d %H:%M:%S"))
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    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 = "Notification", 
        message = "May your journey be smooth and your future bright. Keep your passion and explore the world. May all your efforts be rewarded and you become the person you want to be. Good luck!"
    })

    -- 添加组件到窗口
    page1:add(box)

    -- 注册窗口到UI系统
    ui.add(page1)

    -- 启动exeasyui刷新主循环
    while true do
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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)

    -- 启动exeasyui刷新主循环
    while true do
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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 = "Enter password...",
        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 = "Show",
        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 "Hide" or "Show")
        end
    })

    -- 添加组件到窗口
    page1:add(password_input)
    page1:add(btn_password_toggle)

    -- 注册窗口到UI系统
    ui.add(page1)

    -- 启动exeasyui刷新主循环
    while true do
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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)

    -- 启动exeasyui刷新主循环
    while true do
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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)

    -- 启动exeasyui刷新主循环
    while true do
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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 Box Page",
        message = "Click button to show message box",
        buttons = {}  -- 空按钮数组,不显示按钮
    })

    -- 创建"弹出消息框"按钮
    local btn = ui.button({
        x = 20, y = 140,
        w = 180, h = 50,
        text = "Show Message Box",
        on_click = function()
            -- 创建消息框
            local box = ui.message_box({
                x = 40, y = 210,
                w = 240, h = 120,
                title = "Info",
                message = "This is a message",
                buttons = { "OK", "Cancel" },
                on_result = function()
                    -- 处理按钮点击逻辑
                end
            })
            ui.add(box)
        end
    })

    -- 创建"返回"按钮
    local back = ui.button({
        x = 220, y = 140,
        w = 80, h = 50,
        text = "Back",
        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 = "Check Box Page", 
        message = "Demonstrating multiple check_boxes", 
        buttons = {} 
    })

    -- 创建三个复选框
    local cb1 = ui.check_box({ x = 20, y = 120, text = "Option A" })
    local cb2 = ui.check_box({ x = 20, y = 160, text = "Option B", checked = true })
    local cb3 = ui.check_box({ x = 20, y = 200, text = "Option C" })

    -- 创建返回按钮
    local back = ui.button({
        x = 20, y = 260,
        w = 120, h = 40,
        text = "Back to Home",
        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 = "Check Box Demo",
        on_click = function()
            home:show_subpage("page2")
        end
    })

    -- 创建导航按钮2:进入消息框示例页面  
    local btn2 = ui.button({
        x = 20, y = 130,
        w = 280, h = 50,
        text = "Message Box Demo",
        on_click = function()
            home:show_subpage("page1")
        end
    })

    -- 创建功能按钮:移除复选框子界面(演示销毁功能)
    local btnRemove = ui.button({
        x = 20, y = 200,
        w = 280, h = 50,
        text = "Remove Check Box Page",
        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)

    -- 启动exeasyui刷新主循环
    while true do
        ui.refresh()
        sys.wait(30)
    end
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)

    -- 启动exeasyui刷新主循环
    while true do 
        -- 刷新显示
        ui.refresh()
        -- 等待30ms
        sys.wait(30)
    end
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

    log.info("h",page_h,"w", page_w)
    -- 创建纵向滑动窗口
    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)

    -- 启动exeasyui刷新主循环
    while true do
        ui.refresh()
        sys.wait(30)
    end
end

sys.taskInit(ui_main)

七、显示效果展示

7.1 硬件准备

  1. 按照硬件接线表连接所有设备
  2. 确保电源连接正确,通过TYPE-C USB口供电
  3. 检查所有接线无误,避免短路

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")  --页面切换演示

7.3 软件烧录

  1. 使用Luatools烧录最新内核固件
  2. 下载并烧录本项目所有脚本文件
  3. 将字体文件和图片文件随脚本文件一起烧录到脚本分区
  4. 烧录成功后设备自动重启后开始运行

7.4 功能测试

所有组件综合演示(带滚动功能,使用默认12号英文点阵字体)

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 模拟器--点击开始下载(非刷机)

8.3 下载底层固件和上层运行脚本

1、下载运行所需固件,点击资源管理--选择 Air780EPM 的 LuatOS 固件--下载最新版本的 1 号固件

2、下载本演示 demo 内所有.lua 脚本文件、images 文件夹内的图片

8.4 使用 LuatOS-PC 模拟器仿真 运行 exeasyui 演示 demo

1、返回 Luatloos 工具首页,点击--项目管理测试

2、创建一个项目并命名

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

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、 调试技巧

  • 使用 log.info() 输出调试信息
  • 检查系统内存使用情况
  • 逐步启用组件排查问题