01LVGL图形界面库
一、LVGL(Light and Versatile Graphics Library) 概念
欢迎阅读LVGL中文开发手册! — LVGL 文档 (中文翻译手册)
LVGL: Light and Versatile Graphics Library — LVGL documentation (官方手册)
GitHub - lvgl/lvgl: Embedded graphics library to create beautiful UIs for any MCU, MPU and display type. (源码官网)
LVGL 是最流行的免费开源嵌入式图形库,可以为任何 MCU、MPU 和显示类型创建漂亮的 UI。
它得到了行业领先供应商和项目的支持,如 Arm、STM32、NXP、Espressif、Nuvoton、Arduino、RT-Thread、Zephyr、NuttX、Adafruit 等。
功能丰富
它拥有创建现代美观 GUI 的所有功能:30 多个内置控件、强大的样式系统、Web 启发的布局管理器和支持多种语言的排版系统。
要将 LVGL 集成到您的平台中,您只需要至少 32 KB RAM 和 128 KB Flash、C 编译器、
帧缓冲区和至少 1/10 屏幕大小的渲染缓冲区。
功能介绍
强大的构建模块,例如
按钮、图表、列表、滑块、图像 等。
具有动画、抗锯齿、不透明度、平滑滚动的高级图形
各种输入设备,如触摸板、鼠标、键盘、编码器等
支持多语言,采用 UTF-8 编码
支持多显示器,甚至支持混合颜色格式
完全可定制的图形元素,具有类似 CSS 的样式
硬件无关:可与任何微控制器或显示器一起使用
可扩展:能够在内存较少的情况下运行(64 kB Flash,16 kB RAM)
支持但不要求
操作系统、外部内存和 GPU
即使使用高级图形效果也能进行单帧缓冲操作
用 C 语言编写,以实现最大兼容性(兼容 C++)
模拟器
可在没有嵌入式硬件的 PC 上开始嵌入式 GUI 设计
在模拟器下开发的用户代码可以与固件共享,使 UI 开发更高效
绑定到
MicroPython
教程、示例、主题,用于快速 GUI 设计
文档可在线获取
在 MIT 许可证下免费开源
二、LVGL 登神之路
Get started(开始) — LVGL 文档
1.下载LVGL 工程
配置文件
下载 lv_port_linux 配置文件 把 lvgl 文件夹放入该配置文件中即可使用!
GitHub - lvgl/lv_port_linux: LVGL configured to work with a standard Linux framebuffer
命令下载方式 git clone https://github.com/lvgl/lv_port_linux.git cd lv_port_linux/ git submodule update --init --recursive
提示:下载步骤不用操作知道如何下载即可。
直接使用下载好的源码包
2.升级WSL版本为 WSL2
旧版 WSL 的手动安装步骤 | Microsoft Learn 官方更新教程
更新WSL版本
C:\Users\Administrator>wsl -l -v #查看当前的WSL 版本
NAME STATE VERSION
* Ubuntu-22.04 Stopped 1
C:\Users\Administrator>wsl --set-default-version 2 #设置默认版本为 2
有关与 WSL 2 关键区别的信息,请访问 https://aka.ms/wsl2
操作成功完成。
C:\Users\Administrator>wsl --set-version Ubuntu-22.04 2 #设置 ubuntu-22.04 版本为 2
有关与 WSL 2 关键区别的信息,请访问 https://aka.ms/wsl2
正在进行转换,这可能需要几分钟时间。
C:\Users\Administrator>wsl --update #更新WSL系统
正在检查更新。
已安装最新版本的适用于 Linux 的 Windows 子系统。
成功如图
3.安装SDL库
sudo apt-get update #更新软件源
sudo apt-get install libsdl2-dev #安装SDL库
成功如图
4.编译&运行模拟器
tar -xvf lv_port_linux_ubuntu_sdl.tar.bz -C ~/ #解压源码到家目录
cd ~/lv_port_linux/ #进入源码目录
make clean #清空文件
make -j12 #启动12个线程编译
./build/bin/main #运行例子程序
显示如图界面则安装模拟器成功
三、LVGL 工程分析
main.c主函数
#include "lvgl/lvgl.h"
#include "lvgl/demos/lv_demos.h"
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
// 获取一个环境变量的值
static const char * getenv_default(const char * name, const char * dflt)
{
return getenv(name) ?: dflt;
}
// 配置当前的显示器
#if LV_USE_LINUX_FBDEV
static void lv_linux_disp_init(void)
{
const char * device = getenv_default("LV_LINUX_FBDEV_DEVICE", "/dev/fb0");
lv_display_t * disp = lv_linux_fbdev_create();
lv_linux_fbdev_set_file(disp, device);
}
#elif LV_USE_LINUX_DRM
static void lv_linux_disp_init(void)
{
const char * device = getenv_default("LV_LINUX_DRM_CARD", "/dev/dri/card0");
lv_display_t * disp = lv_linux_drm_create();
lv_linux_drm_set_file(disp, device, -1);
}
#elif LV_USE_SDL
static void lv_linux_disp_init(void)
{
const int width = atoi(getenv("LV_SDL_VIDEO_WIDTH") ?: "800");
const int height = atoi(getenv("LV_SDL_VIDEO_HEIGHT") ?: "480");
lv_sdl_window_create(width, height);
}
#else
#error Unsupported configuration
#endif
int main(void)
{
lv_init(); // 初始化LVGL库
/*Linux display device init*/
lv_linux_disp_init(); // 初始化显示器
// init input device 初始化输入设备
lv_sdl_mouse_create(); // 鼠标
lv_sdl_keyboard_create(); // 键盘
lv_sdl_mousewheel_create(); // 滚轮
/*Create a Demo 创建示例*/
// lv_example_button_1();
// lv_demo_widgets();
// lv_example_ime_pinyin_2();
/*Handle LVGL tasks 处理lvgl任务*/
while(1) {
lv_timer_handler();
usleep(5000);
}
return 0;
}
lv_conf.h 配置文件
注意注意注意:修改了lv_conf.h 配置文件后,必须要make clean ,再make 才能生效
/*Color depth: 8 (A8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888) 设置像素点色深*/
#define LV_COLOR_DEPTH 16
/*API for fopen, fread, etc 设置文件IO读取盘符*/
#define LV_USE_FS_STDIO 1
#if LV_USE_FS_STDIO
#define LV_FS_STDIO_LETTER 'A' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
#define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/
#define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
#endif
/*Use SDL to open window on PC and handle mouse and keyboard 配置SDL的显示框架*/
#define LV_USE_SDL 1
/*Driver for /dev/fb*/ 配置linux 的显示框架
#define LV_USE_LINUX_FBDEV 0
四、LVGL 基本对象概念
在LVGL 图形库中所有看见的东西都是一个 对象lv_obj_t * parent 每个对象都拥有,位置大小,事件 ... 等内容。
Base object(基础对象) (lv_obj) — LVGL 文档
//获取当前活跃的屏幕对象
lv_obj_t * lv_screen_active(void)
//加载活跃的屏幕对象
void lv_screen_load(struct _lv_obj_t * scr);
//创建一个对象
lv_obj_t *lv_obj_create(lv_obj_t *parent)
parent:父亲对象,一个子对象都必须有一个父对象,否则该对象就是一个新的屏幕
返回值:lv_obj_t *新的对象
//删除对象
void lv_obj_delete(lv_obj_t *obj)
//对象大小设置
lv_obj_set_width(obj, new_width) 设置宽度
lv_obj_set_height(obj, new_height) 设置高度
lv_obj_set_size(obj, new_width, new_height) 设置宽度与高度
//对象位置设置
lv_obj_set_x(obj, new_x) 设置X轴坐标
lv_obj_set_y(obj, new_y) 设置Y轴坐标
lv_obj_set_pos(obj, new_x, new_y) 设置 X 与 Y 坐标
//例子:在屏幕中创建一个对象
lv_obj_t *screen = lv_screen_active();
lv_obj_t *myobj =lv_obj_create(screen);
对齐规则
/** Alignments*/
enum _lv_align_t {
LV_ALIGN_DEFAULT = 0,
LV_ALIGN_TOP_LEFT, 上左
LV_ALIGN_TOP_MID, 上中
LV_ALIGN_TOP_RIGHT, 上右
LV_ALIGN_BOTTOM_LEFT,
LV_ALIGN_BOTTOM_MID,
LV_ALIGN_BOTTOM_RIGHT,
LV_ALIGN_LEFT_MID,
LV_ALIGN_RIGHT_MID,
LV_ALIGN_CENTER, 居中
LV_ALIGN_OUT_TOP_LEFT, 外上左
LV_ALIGN_OUT_TOP_MID, 外上中
LV_ALIGN_OUT_TOP_RIGHT,
LV_ALIGN_OUT_BOTTOM_LEFT,
LV_ALIGN_OUT_BOTTOM_MID,
LV_ALIGN_OUT_BOTTOM_RIGHT,
LV_ALIGN_OUT_LEFT_TOP,
LV_ALIGN_OUT_LEFT_MID,
LV_ALIGN_OUT_LEFT_BOTTOM,
LV_ALIGN_OUT_RIGHT_TOP,
LV_ALIGN_OUT_RIGHT_MID,
LV_ALIGN_OUT_RIGHT_BOTTOM,
};
void lv_obj_set_align(lv_obj_t *obj, lv_align_t align) 设置对齐位置
void lv_obj_align(lv_obj_t *obj, lv_align_t align, int32_t x_ofs, int32_t y_ofs) ✔️设置对齐位置和偏移量
void lv_obj_align_to(lv_obj_t *obj, const lv_obj_t *base, lv_align_t align, int32_t x_ofs, int32_t y_ofs) ✔️根据base参考位置设置对齐
obj:需要设置的对象
base:参考位置
align:对齐规则
x_ofs:x 轴偏移量
y_ofs:y 轴偏移量
void lv_obj_center(lv_obj_t *obj) 快速放置中央
父子结构
一个父对象可以被视为其子对象的容器。每个对象都都必须会有且仅有一个父对象(屏幕除外),但一个父对象可以有任意数量的子对象。
lv_obj_t * parent = lv_obj_create(lv_screen_active()); /* 在当前屏幕上创建一个父对象 */
lv_obj_set_size(parent, 100, 80); /* 设置父对象的大小 */
lv_obj_t * obj1 = lv_obj_create(parent); /* 在先前创建的父对象上创建一个对象 */
lv_obj_set_pos(obj1, 10, 10); /* 设置新对象的位置 */
lv_obj_set_parent(obj, new_parent) :设置一个父亲对象
lv_obj_get_child(parent, idx) :获取当前的孩子对象
lv_obj_t *lv_obj_get_parent(const lv_obj_t *obj) :获取当前父亲对象
uint32_t lv_obj_get_child_count(const lv_obj_t *obj) :获取孩子数
demo父子对象操作
lv_obj_t * parent = lv_obj_create(lv_screen_active());
lv_obj_set_size(parent, 300, 300);
lv_obj_center(parent);
lv_obj_t * obj = lv_obj_create(lv_screen_active());
lv_obj_set_pos(obj, 100, 0);
lv_obj_t * obj1 = lv_obj_create(lv_screen_active());
lv_obj_set_pos(obj1, 200, 0);
lv_obj_t * obj2 = lv_obj_create(lv_screen_active());
lv_obj_set_pos(obj2, 300, 0);
// 设置一个父亲对象
lv_obj_set_parent(obj, parent);
lv_obj_set_parent(obj1, parent);
lv_obj_set_parent(obj2, parent);
//获取当前父亲对象的孩子数
int child_count = lv_obj_get_child_count(parent);
printf("child_count=%d\n", child_count);
//打印对象地址
printf("obj= %p\n", obj);
printf("obj1= %p\n", obj1);
printf("obj2= %p\n", obj2);
//获取子对象的地址
for(int i = 0; i < child_count; i++) {
printf("child=%p\n", lv_obj_get_child(parent, i));
}
至此,希望看完这篇文章的你有所收获,我是Bardb,译音八分贝,道友,下期见