【LVGL】学习笔记--(2)GUI Guider的使用
基于上一篇【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL,已经成功地移植了LVGL到我们的嵌入式板子上,并配合磁控旋钮编码器(或者诸如触摸屏、按键、键盘等其他输入设备均可),实现了简单界面的显示工作。
这一章将学习用GUI Guider设计界面以实现旋钮控制界面上控件的操作以及进行界面切换,在这个过程中体会GUI Guider的作用。
一 GUI Guider简介
GUI Guider是恩智浦提供的用户友好型图形用户界面开发工具,可通过开源LVGL图形库快速开发高品质的显示。GUI Guider的拖放编辑器可以轻松利用LVGL的众多特性,如小部件、动画和样式来创建GUI,而只需少量代码或根本无需任何代码。
特点如下:
支持拖放的所见即所得UI设计;
利用并搜索LVGL的各种小部件,轻松创建GUI应用
自定义并配置小部件属性,可自定义您的设计
轻松添加事件、动作和动画来增强您的应用
导入图像和自定义字体的内置资源管理
为MCUXpresso IDE和IAR Embedded Workbench项目生成应用代码
恩智浦评估工具包可用的模板
集成的演示应用,可帮助您开始设计
在支持的平台上利用PXP和VGLite加速的选项
下载路径:NXP官方下载
二 新建工程
下载安装不赘述,装好之后可以右上角修改为中文。新建工程步骤如下:
左上角文件-->新建,选择对应的LVGL版本,点击下一步:

选择设备模板为PC端仿真器:

选择一个应用模板,我这边选择了第一个“按键计数器”:

填写工程信息:

创建成功:

界面的基本操作以及控件的创建等这边不介绍了,全中文而且选项也不多,自己点一点看一下就知道了。
三 界面设计
由于想测试一下界面的切换,所以这边一下创建了三个页面,在其中添加了不同的控件,如下所示:
界面一screen:
其作用是按加、减按钮,文本做对应的数据变化。NEXT按钮添加事件,切换到界面二:

界面二screen1:
其作用是拖动滑块,文本框做对应的数据变化。BACK/NEXT按钮添加事件,分别切换到界面一/界面三:

界面三screen2:
其作用是BACK按钮添加事件,分别切换到界面二:

完成上述设计之后,点击运行调用模拟器并生成界面文件:


四 代码移植
【1】目录结构
GUI Guider经过编译运行之后,生成的代码如下:
custom.c为用户自定义API,这个文件的内容事先由用户写进去,不随着工程的编译修改而变化;
event_init.c为事件触发API;
gui_guider.c为界面引导API;
setup_scr_screen.c/setup_scr_screen_1.c/setup_scr_screen_2.c为界面的初始化API;
界面上用到的字体、图片等资源均在generated文件夹中;

【2】移植到Keil
将custom、generated这两个文件夹整体复制到自己的工程目录下:

Keil中创建GUI/LVGL/GEN组,将上面的源文件全部包含进来,包括用到的字体文件、图片文件:

【3】适配修改
我这边用到了外部输入设备磁控旋钮编码器,所以这边需要做两处修改:
需要将各个界面中要操作的控件,挂载在一个Group下。我这边有三个界面,所以一共创建了三个Group(groupRect/groupRect1/groupRect2);
由于每个界面对应一个组,所以界面切换过程中,输入设备需要重新绑定Group。以上的控件挂载以及输入设备绑组的操作可以放在初始化函数中;
适配界面切换的代码修改如下:
/* 界面一的初始化在setup_scr_screen.c中 */
extern lv_indev_t * indev_encoder;
lv_group_t *groupRect;void setup_scr_screen(lv_ui *ui){//...//绑定组1和设备groupRect = lv_group_create(); //创建组1//挂载组1的控件,包括加减按钮以及指向下一个界面的按钮lv_group_add_obj(groupRect,guider_ui.screen_plus);lv_group_add_obj(groupRect,guider_ui.screen_minus);lv_group_add_obj(groupRect,guider_ui.screen_next);//绑定外部设备lv_indev_set_group(indev_encoder,groupRect);//Init events for screenevents_init_screen(ui);
}/* 界面二的初始化在setup_scr_screen_1.c中 */
extern lv_indev_t * indev_encoder;
lv_group_t *groupRect1;void setup_scr_screen_1(lv_ui *ui){//...//绑定组2和设备groupRect1 = lv_group_create(); //创建组2//挂载组2的控件,包括指向前一个/下一个界面的按钮和滑块lv_group_add_obj(groupRect1,guider_ui.screen_1_back);lv_group_add_obj(groupRect1,guider_ui.screen_1_slider_1);lv_group_add_obj(groupRect1,guider_ui.screen_1_next_1);//绑定外部设备lv_indev_set_group(indev_encoder,groupRect1);//Init events for screenevents_init_screen_1(ui);
}/* 界面三的初始化在setup_scr_screen_2.c中 */
extern lv_indev_t * indev_encoder;
lv_group_t *groupRect2;void setup_scr_screen_2(lv_ui *ui){//...//绑定组3和设备groupRect2 = lv_group_create(); //创建组3//挂载组3的控件,包括指向前一个界面的按钮以及列表List控件的各个条目itemslv_group_add_obj(groupRect2,guider_ui.screen_2_btn_1);lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item0);lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item1);lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item3);lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item4);lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item5);lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item6);//绑定外部设备lv_indev_set_group(indev_encoder,groupRect2);//Init events for screenevents_init_screen_2(ui);
}【4】调用引导
在主任务中包含头文件并调用引导函数:
#include "gui_guider.h"
#include "events_init.h"
#include "custom.h" //用到用户自定义的API才需要调用
lv_ui guider_ui;void GUI_Task(void)
{//LVGL初始化lv_init();//显示器初始化lv_port_disp_init();//外部输入初始化lv_port_indev_init();//设计小部件的ui布局setup_ui(&guider_ui);//设置小部件的事件events_init(&guider_ui);//运行自定义的程序(用到用户自定义的API才需要调用)//custom_init(&guider_ui);while(1){knob_now = knobPosNow(); //确定旋钮当前位置knob_state_now = Knob_State_Entry(&knob_old, &knob_now, knob_state_old); //确定旋钮当前状态if(KNOB_ESCAPE == knob_state_now){knob_state_old = knob_state_now;}else{knob_old = knob_now;knob_state_old = knob_state_now;}lv_task_handler();os_dly_wait(5);}
}
【5】测试效果
测试效果如下:

五 用户自定义API
用户自定义的API在custom.c中。
【1】自定义API
新加了一个界面,其初始化和事件声明均在custom_init中(因为只是简单地示例怎么用custom.c,这边就不绑定外部设备了):
/*** @file custom.c**//********************** INCLUDES*********************/
#include <stdio.h>
#include "lvgl.h"
#include "custom.h"/********************** DEFINES*********************//*********************** TYPEDEFS**********************//*********************** STATIC PROTOTYPES**********************//*********************** STATIC VARIABLES
**********************/
static void event_cb(lv_event_t * e)//事件声明
{LV_LOG_USER("Clicked");static uint32_t cnt = 1;lv_obj_t * btn = lv_event_get_target(e);lv_obj_t * label = lv_obj_get_child(btn, 0);lv_label_set_text_fmt(label, "%"LV_PRIu32, cnt);cnt++;
}/*** Create a demo application*/
void lv_example_event_1(void) //创建一个带标签的按钮
{lv_obj_t * btn = lv_btn_create(lv_scr_act());lv_obj_set_size(btn, 100, 50);lv_obj_center(btn);lv_obj_add_event_cb(btn, event_cb, LV_EVENT_CLICKED, NULL);//把刚才的回调函数添加到按钮上lv_obj_t * label = lv_label_create(btn);lv_label_set_text(label, "Click me!");lv_obj_center(label);
}void custom_init(lv_ui *ui)
{/* Add your codes here */lv_example_event_1();
}【2】调用引导
在主任务中调用custom_init(&guider_ui)即可。
【3】测试效果
GUI Guider模拟器中运行效果:

实际运行效果:

注1:因为没有绑定外部设备,且没有注册到界面一里面去,所以不能实际操作,同时界面一切换就没了。更多的用法有待继续发掘;
注2:实际屏幕出来的颜色,有些与模拟器存在差别,因为影响不大,所以没有继续深究,如果有知道知道原因的大神看到,还望在评论区里不吝赐教;
六 附录
本文涉及的GUI Guider例程文件已经整理打包好:
GUI Guider使用例程(应用LVGL的三个界面切换)
相关文章:
【LVGL】学习笔记--(2)GUI Guider的使用
基于上一篇【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL,已经成功地移植了LVGL到我们的嵌入式板子上,并配合磁控旋钮编码器(或者诸如触摸屏、按键、键盘等其他输入设备均可),实现了简单界面的显示工作。这一章将学习…...
OpenCV-PyQT项目实战(6)项目案例02:滚动条应用
欢迎关注『OpenCV-PyQT项目实战 Youcans』系列,持续更新中 OpenCV-PyQT项目实战(1)安装与环境配置 OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战(3)信号与槽机制 …...
3 决策树及Python实现
1 主要思想 1.1 数据 1.2 训练和使用模型 训练:建立模型(树) 测试:使用模型(树) Weka演示ID3(终端用户模式) 双击weka.jar选择Explorer载入weather.arff选择trees–>ID3构建树…...
小程序和Vue+uniapp+unicloud培训课件
文章目录**一、什么是小程序****1.1** **小程序简介****1.2** **小程序的特点****1.3** **小程序的开发流程**个人小程序和企业小程序的区别1.4 小程序代码构成1.4.1 JSON 配置1.4.2 WXML 模板**数据绑定**逻辑语法条件逻辑列表渲染模板引用共同属性1.4.3 WXSS 样式1.4.4 JS 逻…...
C语言--指针进阶2
目录前言函数指针函数指针数组指向函数指针数组的指针回调函数前言 本篇文章我们将继续学习指针进阶的有关内容 函数指针 我们依然用类比的方法1来理解函数指针这一全新的概念,如图1 我们用一段代码来验证一下: int Add(int x, int y) {return xy;…...
【步进电机和 Arduino】
【步进电机和 Arduino】 前言1. 什么是步进电机及其工作原理?1.1 步进电机结构1.2 绕线方式1.3 通电方式2. 如何使用Arduino和A17步进驱动器控制NEMA4988步进电机2.1 A4988 和 Arduino 连接2.2 测量AB相2.3 A4988 限流3. 步进电机和 Arduino3.1 示例代码 13.2 示例代码 24. 使…...
【面试一:|和||、和区别】
相同点: ||和&&都是逻辑运算符,而|和&是位运算符。位运算符的优先级要比逻辑运算符的优先级高。 &和&&的区别 &和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运…...
【一天一门编程语言】使用汇编语言实现斐波那契数列
文章目录使用汇编语言实现斐波那契数列一、什么是斐波那契数列二、如何用汇编语言实现斐波那契数列一、汇编语言概念1.1 什么是汇编语言1.2 汇编语言的特点二、汇编语言指令2.1 简单指令2.2 复杂指令汇编语言程序结构代码实例指令集常用指令指令代码实例使用汇编语言实现斐波那…...
RabbitMQ实现死信队列
目录死信队列是什么怎样实现一个死信队列说明实现过程导入依赖添加配置编写mq配置类添加业务队列的消费者添加死信队列的消费者添加消息发送者添加消息测试类测试死信队列的应用场景总结死信队列是什么 “死信”是RabbitMQ中的一种消息机制,当你在消费消息时&#…...
【Linux】安装Tomcat教程
目录 1.上传安装包 2.解压安装包 3.启动Tomcat 4.查看启动日志 5.查看进程 6.开放端口 7.停止Tomcat 1.上传安装包 使用FinalShell自带的上传工具将Tomcat的二进制发布包上传到Linux(与前面上传JDK安装包步骤 一致)。 2.解压安装包 将上传上来的安装包解压到指定目录…...
学习笔记之Vuex(五)
Vuex(五)Vuex一、什么是Vuex二、Vuex工作原理三、搭建Vuex环境四、求和案例分析4.1 求和案例——vue实现4.2 求和案例——vuex实现(五)Vuex 一、什么是Vuex 1.概念 在Vue中实现集中式状态(数据)管理的一…...
SSM知识快速复习
SSM知识快速复习SpringIOCDIIOC容器在Spring中的实现常用注解Autowired注解的原理AOP相关术语作用动态代理实现原理事务Transactional事务属性:只读事务属性:超时事务属性:回滚策略事务属性:事务隔离级别事务属性:事务…...
【Linux】安装MySQL
目录 1.检测当前系统是否安装过MySQL相关数据库 2. 卸载现有的MySQL数据库 3.上传解压 4.顺序安装rpm包 5.启动MySQL 6.查看临时密码 7.登录MySQL 8.开放端口 1.检测当前系统是否安装过MySQL相关数据库 需要通过rpm相关指令,来查询当前系统中是否存在已安…...
【深度学习】手把手教你开发自己的深度学习模板
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言1数据相关1.1 数据初探1.2.数据处理1.3 数据变形2 定义网络,优化函数3. 训练前言 入坑2年后,重新梳理之前的知识,发现其实需…...
一个诡异的 Pulsar InterruptedException 异常
背景 今天收到业务团队反馈线上有个应用往 Pulsar 中发送消息失败了,经过日志查看得知是发送消息时候抛出了 java.lang.InterruptedException 异常。 和业务沟通后得知是在一个 gRPC 接口中触发的消息发送,大约持续了半个小时的异常后便恢复正常了&…...
Java岗面试题--Java并发(volatile 专题)
目录1. 面试题一:谈谈 volatile 的使用及其原理补充:内存屏障volatile 的原理2. 面试题二:volatile 为什么不能保证原子性3. 面试题三:volatile 的内存语义4. 面试题四:volatile 的实现机制5. 面试题五:vol…...
Java---打家劫舍ⅠⅡ
目录 打家劫舍Ⅰ 题目分析 代码一 代码二 打家劫舍Ⅱ 打家劫舍Ⅰ 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被…...
MySQL Lesson4
1:关于查询结果集的去重(distinct) select distinct job from emp; **distinct只能出现在所有字段的最前面。所表示的含有是所有的结果联合起来去重。 select distinct deptno,job from emp order by deptno; select count(distinct job)from…...
浅谈权限获取方法之文件上传
概述 文件上传漏洞是发生在有上传功能的应用中,如果应用程序对用户的上传文件没有控制或者存在缺陷,攻击者可以利用应用上传功能存在的缺陷,上传木马、病毒等有危害的文件到服务器上面,控制服务器。 漏洞成因及危害 文件上传漏…...
资产设备防拆标签安全防护和资产定位解决方案
随着社会经济的发展和高新技术的日新月异,对各方面的安全要求也在不断地提高,以物联网安防、入侵报警和出入口控制、应急系统等为主的安全防范系统日益成为各类文物场所智能化弱电工程不可或缺的组成部分,是重点资产管理场所内加强管理和安全…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
