【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…...

浅谈权限获取方法之文件上传
概述 文件上传漏洞是发生在有上传功能的应用中,如果应用程序对用户的上传文件没有控制或者存在缺陷,攻击者可以利用应用上传功能存在的缺陷,上传木马、病毒等有危害的文件到服务器上面,控制服务器。 漏洞成因及危害 文件上传漏…...

资产设备防拆标签安全防护和资产定位解决方案
随着社会经济的发展和高新技术的日新月异,对各方面的安全要求也在不断地提高,以物联网安防、入侵报警和出入口控制、应急系统等为主的安全防范系统日益成为各类文物场所智能化弱电工程不可或缺的组成部分,是重点资产管理场所内加强管理和安全…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...

篇章二 论坛系统——系统设计
目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...

海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》
近日,嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》,海云安高敏捷信创白盒(SCAP)成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天,网络安全已成为企业生存与发展的核心基石,为了解…...