关于一个基于 LVGL (Light and Versatile Graphics Library) 的文件浏览器应用,主要功能是浏览目录结构并显示图片文件。以下是代码的详细解析:
·
main.c代码
#include "lvgl/lvgl.h" // 包含LVGL核心库头文件
#include "lvgl/demos/lv_demos.h" // 包含LVGL演示程序头文件
#include "lv_drivers/display/fbdev.h" // 包含帧缓冲设备驱动头文件
#include "lv_drivers/indev/evdev.h" // 包含输入设备驱动头文件
#include <unistd.h> // 包含UNIX标准函数头文件(如usleep)
#include <pthread.h> // 包含线程相关函数头文件
#include <dirent.h> // 包含目录操作相关函数头文件
#include <time.h> // 包含时间相关函数头文件
#include <sys/time.h> // 包含系统时间相关函数头文件
#include <stdio.h> // 包含标准输入输出函数头文件
#include <stdlib.h> // 包含标准库函数头文件(如malloc)
#define DISP_BUF_SIZE (128 * 1024) // 定义显示缓冲区大小为128KB
#define BASE_START_OBJ_DIR "/" // 定义起始目录路径为根目录
typedef struct demo_inf // 定义演示程序信息结构体
{
lv_obj_t * main_windows; // 主窗口对象指针
lv_obj_t * dir_list; // 目录列表对象指针
lv_obj_t * little_windows; // 右侧小窗口对象指针
}DI,*P_DI; // 定义结构体别名及指针别名
struct tmp_inf // 定义临时信息结构体(用于事件传递数据)
{
P_DI p_di; // 演示程序信息结构体指针
char base_dir_path[256]; // 基础目录路径
};
// 函数声明
P_DI Demo_Init(); // 创建主画布并初始化
int Show_File_List(const char * obj_dir_path,P_DI p_di); // 显示文件列表
void Close_Img_Btn(lv_event_t *event); // 关闭图片按钮回调函数
void Press_Pic_Btn(lv_event_t *event); // 点击图片按钮回调函数
void Press_Dir_Btn(lv_event_t *event); // 点击目录按钮回调函数
P_DI Demo_Init() // 初始化演示程序界面
{
P_DI p_di = (P_DI)malloc(sizeof(DI)); // 为演示信息结构体分配内存
if(p_di == (P_DI)NULL) // 检查内存分配是否成功
{
perror("malloc ..."); // 分配失败时输出错误信息
return (P_DI)-1; // 返回错误值
}
memset(p_di,0,sizeof(DI)); // 初始化结构体内存为0
p_di->main_windows = lv_obj_create(NULL); // 创建主窗口对象(父对象为NULL)
p_di->dir_list = lv_list_create(p_di->main_windows); // 在主窗口上创建目录列表
p_di->little_windows = lv_obj_create(p_di->main_windows); // 在主窗口上创建右侧小窗口
lv_obj_set_size(p_di->dir_list,300,480); // 设置左侧目录列表大小(宽300,高480)
lv_obj_set_size(p_di->little_windows,480,480); // 设置右侧小窗口大小(宽480,高480)
lv_obj_set_pos(p_di->dir_list,0,10); // 设置目录列表位置(x=0,y=10)
lv_obj_set_pos(p_di->little_windows,310,10); // 设置右侧小窗口位置(x=310,y=10)
lv_scr_load(p_di->main_windows); // 将主窗口加载为当前屏幕
return p_di; // 返回演示信息结构体指针
}
void Press_Dir_Btn(lv_event_t *event) // 目录按钮点击事件处理函数
{
char base_dir_path[256]= "\0"; // 存储基础目录路径的临时变量
P_DI p_di = ((struct tmp_inf *)(event->user_data))->p_di; // 从用户数据中获取演示信息指针
strcpy(base_dir_path,((struct tmp_inf *)(event->user_data))->base_dir_path); // 复制目录路径
free(((struct tmp_inf *)(event->user_data))); // 释放临时信息结构体的内存
printf("%s\n",base_dir_path); // 打印当前目录路径
lv_obj_del(p_di->little_windows); // 删除右侧小窗口对象
lv_obj_del(lv_obj_get_parent(event->current_target)); // 删除当前点击按钮的父对象(列表项)
printf("+++++----\n"); // 调试输出
// 重新创建目录列表和右侧窗口
p_di->dir_list = lv_list_create(p_di->main_windows);
p_di->little_windows = lv_obj_create(p_di->main_windows);
lv_obj_set_size(p_di->dir_list,300,480); // 重新设置左侧目录列表大小
lv_obj_set_size(p_di->little_windows,480,480); // 重新设置右侧小窗口大小
lv_obj_set_pos(p_di->dir_list,0,10); // 重新设置目录列表位置
lv_obj_set_pos(p_di->little_windows,310,10); // 重新设置右侧小窗口位置
Show_File_List(base_dir_path,p_di); // 显示新目录下的文件列表
return ; // 函数返回
}
void Press_Pic_Btn(lv_event_t *event) // 图片按钮点击事件处理函数
{
char base_dir_path[256]= "\0"; // 存储基础目录路径的临时变量
P_DI p_di = ((struct tmp_inf *)(event->user_data))->p_di; // 从用户数据中获取演示信息指针
// 删掉主界面
lv_obj_del(p_di->main_windows); // 删除主窗口对象
free(p_di); // 释放演示信息结构体内存
lv_obj_t * main_draw = lv_obj_create(NULL); // 创建新的主画布对象
lv_obj_t * main_windows = lv_win_create(main_draw,30); // 在新画布上创建窗口(边框半径30)
//lv_obj_set_size(main_windows, LV_HOR_RES, LV_VER_RES); // 注释:设置窗口大小为屏幕分辨率
//lv_obj_align(main_windows, LV_ALIGN_CENTER, 0, 0); // 注释:将窗口居中对齐
lv_obj_t * close_btn = lv_win_add_btn(main_windows,LV_SYMBOL_CLOSE,30); // 添加关闭按钮(符号为关闭,大小30)
lv_obj_set_pos(close_btn,450,10); // 设置关闭按钮位置(x=450,y=10)
lv_obj_add_event_cb(close_btn,Close_Img_Btn,LV_EVENT_SHORT_CLICKED,main_draw); // 为关闭按钮添加点击事件回调
char obj_img_path[256] = "\0"; // 存储图片路径的变量
sprintf(obj_img_path,"%s%s","S:",((struct tmp_inf *)(event->user_data))->base_dir_path); // 拼接图片路径(前缀"S:")
char * obj_p = &obj_img_path[strlen(obj_img_path)-4]; // 获取文件扩展名(最后4个字符)
if(strcmp(obj_p,".gif") == 0) // 判断文件是否为GIF格式
{
// 创建一个图片对象用于显示 GIF 动画
lv_obj_t *gif_img = lv_gif_create(main_draw); // 在新画布上创建GIF对象
// 设置 GIF 图片对象的大小模式为正常大小
lv_img_set_size_mode(gif_img, LV_IMG_SIZE_MODE_REAL);
// 将 GIF 图片对象居中
lv_obj_align(gif_img, LV_ALIGN_CENTER, 0, 0);
lv_gif_set_src(gif_img, obj_img_path); // 设置 GIF 图片路径
}
else // 非GIF格式图片
{
lv_obj_t * img = lv_img_create(main_draw); // 在画布上创建图像对象
lv_obj_align(img,LV_ALIGN_CENTER, 0, 0); // 设置图像居中对齐
lv_img_set_size_mode(img,LV_IMG_SIZE_MODE_REAL); // 设置图像大小模式为实际大小
printf("+++%s+++\n",obj_img_path); // 打印图片路径(调试用)
lv_img_set_src(img,obj_img_path); // 设置图像的路径
}
lv_obj_move_foreground(close_btn); // 将关闭按钮置于顶层(避免被图片遮挡)
lv_scr_load(main_draw); // 将新画布加载为当前屏幕
return; // 函数返回
}
void Close_Img_Btn(lv_event_t *event) // 关闭图片按钮事件处理函数
{
// 删掉图片界面
lv_obj_del((lv_obj_t *)event->user_data); // 删除当前图片界面(用户数据为图片界面对象)
// 重新启动主界面
P_DI p_di = Demo_Init(); // 重新初始化演示程序界面
Show_File_List(BASE_START_OBJ_DIR,p_di); // 显示起始目录的文件列表
return ; // 函数返回
}
int Show_File_List(const char * obj_dir_path,P_DI p_di) // 显示目录下的文件列表
{
DIR * dp = opendir(obj_dir_path); // 打开指定目录
if(dp == (DIR *)NULL) // 检查目录是否打开成功
{
perror("opendir ... "); // 打开失败时输出错误信息
return -1; // 返回错误值
}
char base_path[256]; // 存储文件完整路径的变量
int x=0,y=0; // 右侧小窗口中按钮的坐标变量
while(1) // 循环读取目录项
{
memset(base_path,0,256); // 清空路径变量
struct dirent * eq = readdir(dp); // 读取目录中的一项
if(eq == NULL) // 若读取到目录末尾(无更多项)
{
break; // 退出循环
}
// 拼接完整路径(处理目录路径末尾是否带"/"的情况)
if(obj_dir_path[strlen(obj_dir_path)-1] == '/') // 若目录路径以"/"结尾
{
sprintf(base_path,"%s%s",obj_dir_path,eq->d_name); // 直接拼接目录路径和文件名
}
else // 若目录路径不以"/"结尾
{
sprintf(base_path,"%s/%s",obj_dir_path,eq->d_name); // 拼接目录路径、"/"和文件名
}
struct tmp_inf * ti = (struct tmp_inf *)malloc(sizeof(struct tmp_inf)); // 分配临时信息结构体内存
memset(ti,0,sizeof(struct tmp_inf)); // 初始化临时结构体为0
strcpy(ti->base_dir_path,base_path); // 保存文件完整路径到临时结构体
ti->p_di = p_di; // 保存演示信息结构体指针到临时结构体
if(eq->d_type == DT_DIR) // 判断当前项是否为目录
{
// 在目录列表中添加目录按钮(图标为目录符号,文本为目录名)
lv_obj_t * dir_btn_1 = lv_list_add_btn(p_di->dir_list,LV_SYMBOL_DIRECTORY,eq->d_name);
// 为目录按钮添加点击事件回调(事件类型为短按,用户数据为临时结构体)
lv_obj_add_event_cb(dir_btn_1,Press_Dir_Btn,LV_EVENT_SHORT_CLICKED,ti);
}
else // 当前项为文件
{
// 在目录列表中添加文件按钮(图标为文件符号,文本为文件名)
lv_obj_t * dir_btn_1 = lv_list_add_btn(p_di->dir_list,LV_SYMBOL_FILE,eq->d_name);
// 在右侧小窗口中创建按钮
lv_obj_t * dir_btn_2 = lv_btn_create(p_di->little_windows);
lv_obj_set_size(dir_btn_2,70,70); // 设置按钮大小(70x70)
lv_obj_set_pos(dir_btn_2,x,y); // 设置按钮位置
lv_obj_t *icon = lv_img_create(dir_btn_2); // 在按钮上创建图标对象
lv_img_set_src(icon, LV_SYMBOL_OK); // 设置图标为"OK"符号
// 在右侧小窗口中创建文件名标签
lv_obj_t *label = lv_label_create(p_di->little_windows);
lv_label_set_text(label,eq->d_name); // 设置标签文本为文件名
lv_obj_set_pos(label,x,y+75); // 设置标签位置(在按钮下方)
x+=120; // 下一个按钮的x坐标增加120(留出间距)
if((480-x) <= 70) // 若右侧空间不足(小于按钮宽度)
{
x = 0; // 重置x坐标为0(换行)
y+= 100; // y坐标增加100(留出按钮和标签的高度)
}
char * obj_p = &eq->d_name[strlen(eq->d_name)-4]; // 获取文件扩展名(最后4个字符)
// 判断文件是否为图片格式(.bmp/.gif/.jpg/.png)
if((strcmp(obj_p,".bmp") == 0) || (strcmp(obj_p,".gif") == 0) || (strcmp(obj_p,".jpg") == 0) || (strcmp(obj_p,".png") == 0))
{
// 为图片文件按钮添加点击事件回调
lv_obj_add_event_cb(dir_btn_2,Press_Pic_Btn,LV_EVENT_SHORT_CLICKED,ti);
}
}
}
closedir(dp); // 关闭目录
return 0; // 函数成功返回
}
int main(void) // 程序主函数
{
/*LittlevGL init*/
lv_init(); // 初始化LVGL库
/*Linux frame buffer device init*/
fbdev_init(); // 初始化帧缓冲设备(用于显示)
/*A small buffer for LittlevGL to draw the screen's content*/
static lv_color_t buf[DISP_BUF_SIZE]; // 定义显示缓冲区
/*Initialize a descriptor for the buffer*/
static lv_disp_draw_buf_t disp_buf; // 定义显示缓冲区描述符
lv_disp_draw_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE); // 初始化缓冲区描述符
/*Initialize and register a display driver*/
static lv_disp_drv_t disp_drv; // 定义显示驱动结构体
lv_disp_drv_init(&disp_drv); // 初始化显示驱动
disp_drv.draw_buf = &disp_buf; // 设置驱动使用的缓冲区
disp_drv.flush_cb = fbdev_flush; // 设置刷新回调函数(帧缓冲刷新)
disp_drv.hor_res = 800; // 设置水平分辨率为800
disp_drv.ver_res = 480; // 设置垂直分辨率为480
lv_disp_drv_register(&disp_drv); // 注册显示驱动
evdev_init(); // 初始化输入设备(如触摸屏/鼠标)
static lv_indev_drv_t indev_drv_1; // 定义输入设备驱动结构体
lv_indev_drv_init(&indev_drv_1); // 初始化输入设备驱动
indev_drv_1.type = LV_INDEV_TYPE_POINTER; // 设置输入设备类型为指针设备(如鼠标)
/*This function will be called periodically (by the library) to get the mouse position and state*/
indev_drv_1.read_cb = evdev_read; // 设置输入设备读取回调函数
lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1); // 注册输入设备驱动
/*Set a cursor for the mouse*/
LV_IMG_DECLARE(mouse_cursor_icon) // 声明鼠标光标图标(LVGL宏)
lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); // 创建光标图像对象(父对象为当前屏幕)
lv_img_set_src(cursor_obj, &mouse_cursor_icon); // 设置光标图像源
lv_indev_set_cursor(mouse_indev, cursor_obj); // 将光标图像关联到输入设备
/*Create a Demo*/
//lv_demo_widgets(); // 注释:使用LVGL自带的部件演示
P_DI p_di = Demo_Init(); // 初始化自定义演示程序
Show_File_List(BASE_START_OBJ_DIR,p_di); // 显示起始目录的文件列表
/*Handle LitlevGL tasks (tickless mode)*/
while(1) { //
makefile
#
# Makefile
#
CC = arm-linux-gcc
LVGL_DIR_NAME ?= lvgl
LVGL_DIR ?= ${shell pwd}
CFLAGS ?= -O3 -g0 -I$(LVGL_DIR)/ -Wall -Wshadow -Wundef -Wmissing-prototypes -Wno-discarded-qualifiers -Wall -Wextra -Wno-unused-function -Wno-error=strict-prototypes -Wpointer-arith -fno-strict-aliasing -Wno-error=cpp -Wuninitialized -Wmaybe-uninitialized -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wno-cast-qual -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wformat-security -Wno-ignored-qualifiers -Wno-error=pedantic -Wno-sign-compare -Wno-error=missing-prototypes -Wdouble-promotion -Wclobbered -Wdeprecated -Wempty-body -Wtype-limits -Wstack-usage=2048 -Wno-unused-value -Wno-unused-parameter -Wno-missing-field-initializers -Wuninitialized -Wmaybe-uninitialized -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wtype-limits -Wsizeof-pointer-memaccess -Wno-format-nonliteral -Wpointer-arith -Wno-cast-qual -Wmissing-prototypes -Wunreachable-code -Wno-switch-default -Wreturn-type -Wmultichar -Wno-discarded-qualifiers -Wformat-security -Wno-ignored-qualifiers -Wno-sign-compare
LDFLAGS ?= -lm
BIN = demo
#Collect the files to compile
MAINSRC = ./main.c
#include $(LVGL_DIR)/lvgl/lvgl.mk
#include $(LVGL_DIR)/lv_drivers/lv_drivers.mk
CSRCS +=$(LVGL_DIR)/mouse_cursor_icon.c
OBJEXT ?= .o
AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))
MAINOBJ = $(MAINSRC:.c=$(OBJEXT))
SRCS = $(ASRCS) $(CSRCS) $(MAINSRC)
OBJS = $(AOBJS) $(COBJS)
## MAINOBJ -> OBJFILES
all: default
%.o: %.c
@$(CC) $(CFLAGS) -c $< -o $@
@echo "CC $<"
default: $(AOBJS) $(COBJS) $(MAINOBJ)
$(CC) -o $(BIN) $(MAINOBJ) $(AOBJS) $(COBJS) $(LDFLAGS) ./liblvgl.so.8.2 -L. -Wall
clean:
rm -f $(BIN) $(AOBJS) $(COBJS) $(MAINOBJ)
还需要上传动态库和生成都demo才可以成功运行:如下

解决图片覆盖返回退出按钮被覆盖的问题改y值就可以了,比如我改了30,就没有覆盖退出按键


更多推荐



所有评论(0)