本文理论知识居多,开始一遍了解功能即可,后续用到再当字典查,文中涉及的实操界面,需要先搭建环境,需观看我上一篇文章:创建第一个LVGL工程https://mp.weixin.qq.com/s/zJ8hf4f36GGpJW_8vHf0Jw
想象一下这些场景:
这些都需要使用图像控件来显示!在嵌入式UI中,一图胜千言,好的图像能让界面更直观、更美观。
适用场景:单片机、无文件系统、图片数量少且固定
访问:https://lvgl.io/tools/imageconverter

重要设置:
CF_TRUE_COLOR - 真彩色,效果最好,文件最大CF_TRUE_COLOR_ALPHA - 带透明度的真彩色CF_INDEXED_1/2/4/8BIT - 索引色,文件小但颜色少C array - C数组格式,直接嵌入代码Binary - 二进制格式,需要文件系统支持// 1. 将生成的icon_back.c文件放到工程目录main.c同一路径下// 2. 在代码中声明和使用// 声明图片(在文件顶部)LV_IMG_DECLARE(icon_back);void show_image() { // 创建图像控件 lv_obj_t *img = lv_img_create(lv_scr_act()); // 设置图像源(使用声明的图片) lv_img_set_src(img, &icon_back); // 居中显示 lv_obj_center(img);}优点:运行速度快,不依赖文件系统缺点:图片大小固定,更新麻烦,占用程序空间大

适用场景:Linux嵌入式设备、图片数量多或需要动态更新
你的工程/├── res/ # 资源文件夹│ ├── font/ # 字体文件夹│ ├── image/ # 图片文件夹│ │ ├── image_conf.h│ │ ├── icon_back.png│ │ └── lvgl-logo.png│ └── res_conf.h # 资源配置文件├── main.c└── CMakeLists.txtres_conf.h - 统一管理所有资源路径:
#ifndef _RES_CONF_H_#define _RES_CONF_H_// 区分PC仿真和开发板环境#ifdef SIMULATOR_LINUX // PC仿真路径(相对路径) #define FONT_PATH "./build/app1/res/font/" #define IMAGE_PATH "./build/app1/res/image/"#else // 开发板路径(绝对路径) #define FONT_PATH "/usr/res/font/" #define IMAGE_PATH "/usr/res/image/"#endif#endifimage_conf.h - 图片配置头文件:
#ifndef _IMAGE_CONF_H_#define _IMAGE_CONF_H_#include "res_conf.h"// 定义盘符(LVGL文件系统使用)#define DRIVER_LETTER "A:"// 获取图片完整路径的宏#define GET_IMAGE_PATH(name) (DRIVER_LETTER IMAGE_PATH name)#endifPC仿真环境(platform/x86linux/src/porting/lv_conf.h):
// 启用标准I/O文件系统#define LV_USE_FS_STDIO 1#if LV_USE_FS_STDIO#define LV_FS_STDIO_LETTER 'A' /* 盘符,对应A: */#define LV_FS_STDIO_PATH "" /* 工作目录,为空表示当前目录 */#define LV_FS_STDIO_CACHE_SIZE 0 /* 缓存大小,0表示不缓存 */#endif开发板环境(platform/t113/src/porting/lv_conf.h):
// 根据实际情况配置文件系统#define LV_USE_FS_STDIO 1 // 或LV_USE_FS_POSIX,取决于你的系统#if LV_USE_FS_STDIO#define LV_FS_STDIO_LETTER 'A'#define LV_FS_STDIO_PATH "/usr/res/" // 注意:这里设置基础路径#define LV_FS_STDIO_CACHE_SIZE 0#endifcmake_minimum_required(VERSION 3.15)project(app1)# 定义宏,用于区分PC仿真环境if(SIMULATOR_LINUX) add_compile_definitions(SIMULATOR_LINUX)endif()# 复制资源文件到构建目录file(COPY res DESTINATION ${PROJECT_BINARY_DIR})# 添加源代码aux_source_directory(. SOURCES)add_executable(app1 ${SOURCES})# 添加头文件路径target_include_directories(app1 PRIVATE ./ res/ res/font/ res/image/ ${CMAKE_SOURCE_DIR}/component/font ${CMAKE_SOURCE_DIR}/lvgl)# 链接库target_link_libraries(app1 PRIVATE lvgl font)#include "image_conf.h"void show_image_from_file() { // 创建图像控件 lv_obj_t *img = lv_img_create(lv_scr_act()); // 使用文件路径设置图像源 lv_img_set_src(img, GET_IMAGE_PATH("lvgl-logo.png")); // 居中显示 lv_obj_center(img);}
很多图标是白色背景透明的,在白色背景上显示为"空白"。
解决方案:
void show_transparent_icon() { // 1. 创建黑色背景容器 lv_obj_t *container = lv_obj_create(lv_scr_act()); lv_obj_set_size(container, LV_PCT(100), LV_PCT(100)); lv_obj_set_style_bg_color(container, lv_color_hex(0x000000), LV_PART_MAIN); // 去除容器的边距、边框等 lv_obj_set_style_pad_all(container, 0, LV_PART_MAIN); lv_obj_set_style_border_width(container, 0, LV_PART_MAIN); lv_obj_set_style_outline_width(container, 0, LV_PART_MAIN); lv_obj_set_style_radius(container, 0, LV_PART_MAIN); // 2. 在容器中显示图标 lv_obj_t *img = lv_img_create(container); lv_img_set_src(img, GET_IMAGE_PATH("icon_back.png")); lv_obj_center(img);}原理:透明图标显示为它自身的颜色(通常是白色),在黑色背景上就能清晰可见。

重要:不能使用lv_obj_set_size()设置图像大小!
void scale_image() { lv_obj_t *img = lv_img_create(lv_scr_act()); lv_img_set_src(img, GET_IMAGE_PATH("icon_back.png")); lv_obj_center(img); // 缩放图像 // 256 = 原始大小(100%) 512 = 放大2倍(200%)128 = 缩小一半(50%) lv_img_set_zoom(img, 512); // 放大2倍 // 获取当前缩放值 uint16_t zoom = lv_img_get_zoom(img); printf("当前缩放: %d (%.1f倍)\n", zoom, zoom / 256.0);}
void rotate_image() { lv_obj_t *img = lv_img_create(lv_scr_act()); lv_img_set_src(img, GET_IMAGE_PATH("icon_back.png")); lv_obj_center(img); // 旋转图像(角度精度为0.1度) // 90° = 900 45.8° = 458 180° = 1800 lv_img_set_angle(img, 900); // 旋转90度 // 获取当前旋转角度 uint16_t angle = lv_img_get_angle(img); printf("当前角度: %d (%.1f度)\n", angle, angle / 10.0);}
void transform_image() { lv_obj_t *img = lv_img_create(lv_scr_act()); lv_img_set_src(img, GET_IMAGE_PATH("icon_back.png")); lv_obj_center(img); // 先缩放 lv_img_set_zoom(img, 384); // 1.5倍 // 再旋转 lv_img_set_angle(img, 450); // 45度 // 设置旋转中心点(默认是图像中心) lv_img_set_pivot(img, 50, 50); // 设置旋转中心为(50,50)像素}
默认情况下,图像控件不可点击。我们需要手动添加点击功能:
// 图像点击事件处理函数static void image_click_cb(lv_event_t *e) { printf("图像被点击了!\n"); // 可以获取事件源(被点击的图像) lv_obj_t *img = lv_event_get_target(e); // 根据图像做不同处理 const char *src = lv_img_get_src(img); printf("图像源: %s\n", src); // 切换图像(实现按钮状态切换) if (strstr(src, "lvgl-logo")) { lv_img_set_src(img, GET_IMAGE_PATH("icon_back.png")); } else { lv_img_set_src(img, GET_IMAGE_PATH("lvgl-logo.png")); }}void create_clickable_image() { // 创建图像 lv_obj_t *img = lv_img_create(lv_scr_act()); lv_img_set_src(img, GET_IMAGE_PATH("icon_back.png")); lv_obj_center(img); // 添加可点击标志 lv_obj_add_flag(img, LV_OBJ_FLAG_CLICKABLE); // 绑定点击事件 lv_obj_add_event_cb(img, image_click_cb, LV_EVENT_CLICKED, NULL); // 也可以添加其他事件 lv_obj_add_event_cb(img, image_click_cb, LV_EVENT_PRESSED, NULL); lv_obj_add_event_cb(img, image_click_cb, LV_EVENT_RELEASED, NULL);}
// 创建图像lv_obj_t *img = lv_img_create(parent);// 设置图像源(C数组)LV_IMG_DECLARE(icon);lv_img_set_src(img, &icon);// 设置图像源(文件)lv_img_set_src(img, GET_IMAGE_PATH("icon.png"));// 缩放图像lv_img_set_zoom(img, 512); // 200%// 旋转图像lv_img_set_angle(img, 900); // 90度// 使图像可点击lv_obj_add_flag(img, LV_OBJ_FLAG_CLICKABLE);lv_obj_add_event_cb(img, click_handler, LV_EVENT_CLICKED, NULL);