2、 SDL3 LVGL vscode cmake环境搭建

1、 前置条件

2. LVGL 加入

在SDL测试工程中新建third_party 目录, 将lvgl 复制到这个目录下,删除其他不需要的目录和文件,保留src, examples和根目录下的头文件, 更改包含版本的lvgl-v9.2目录为lvgl
在这里插入图片描述

3. 修改CmakLists.txt

cmake_minimum_required(VERSION 3.30)
project(sdl3_lvgl)

set(CMAKE_C_STANDARD 11)

# 包含目录
include_directories(
    ${CMAKE_SOURCE_DIR}/include
    ${CMAKE_SOURCE_DIR}/third_party/lvgl
    ${CMAKE_SOURCE_DIR}/third_party/lvgl/../
    ${CMAKE_SOURCE_DIR}/third_party/lvgl/src
    # ${CMAKE_SOURCE_DIR}/third_party/lvgl/examples/porting
)


# 递归收集 .c 文件(从指定根目录开始)
# LVGL
file(GLOB_RECURSE LVGL_SRC 
    LIST_DIRECTORIES false  # 忽略目录,仅保留文件
    "${CMAKE_SOURCE_DIR}/third_party/lvgl/src/*.c"
)

# 可选:排除不需要的目录
# list(FILTER SOURCES EXCLUDE REGEX ".*/tests?/.*")  # 排除 test 或 tests 目录


# 源文件
file(GLOB_RECURSE SOURCES 
    LIST_DIRECTORIES false  
    "${CMAKE_SOURCE_DIR}/src/*.c"
)

# 链接库路径
link_directories(${CMAKE_SOURCE_DIR}/lib)

# message(STATUS "Project source dir: ${PROJECT_SOURCE_DIR}")
# message(STATUS "Main.c path: ${PROJECT_SOURCE_DIR}/src/main.c")

# 可执行文件
add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/src/main.c ${SOURCES} ${LVGL_SRC})

# 链接库
target_link_libraries(${PROJECT_NAME}
    SDL3
)


# 拷贝库文件 文件
file(COPY ${PROJECT_SOURCE_DIR}/lib/SDL3.dll DESTINATION ${PROJECT_BINARY_DIR})

4. lvgl 适配

4.1 修改lvgl配置文件

将lv_conf_template.h 预编译指令改为1, 并改文件名为lv_conf.h,不然会找不到这个头文件
在这里插入图片描述

4. lvgl 整合

4.1 引入 lvgl

在这里插入图片描述

4.1 初始化SDL

#define BYTE_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_ARGB8888))
#define WIDTH (600)  // 屏幕宽度
#define HEIGHT (400) // 屏幕高度
#define BUF_HEIGHT 40    // 小行缓冲

static SDL_Window *window;
static SDL_Renderer *renderer;
static SDL_Texture *texture;

static volatile bool running = true;

int initSDL() {
    // 初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        SDL_Log(" SDL init falid : %s", SDL_GetError());
        return -1;
    }

    // 创建窗口
    window = SDL_CreateWindow("SDL3", WIDTH, HEIGHT, SDL_WINDOW_HIGH_PIXEL_DENSITY);

    // // 创建渲染器
    renderer = SDL_CreateRenderer(window, NULL);

    // SDL_CreateWindowAndRenderer("SDL3", HOR, VER, SDL_WINDOW_HIGH_PIXEL_DENSITY, &window, &renderer);

    // 创建纹理
    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, // 改为流式访问
                                WIDTH, HEIGHT);

    if (!window || !renderer || !texture) {
        SDL_Log("initSDL fail: %s", SDL_GetError());
        SDL_Quit();
        running = false;
        return -1;
    }
    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); // 设置背景为白色
    return 0;
}

4.1 初始化并注册显示设备

void disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
    SDL_Rect src_rect = {
        .x = area->x1,
        .y = area->y1,
        .w = area->x2 - area->x1 + 1,
        .h = area->y2 - area->y1 + 1
    };

    // 更新纹理的特定区域
    SDL_UpdateTexture(texture, &src_rect, px_map, WIDTH * BYTE_PER_PIXEL);

    // 渲染整个纹理到窗口
    SDL_RenderTexture(renderer, texture, NULL, NULL);
    lv_display_flush_ready(disp);
}

void lv_port_disp_init(void) {
    lv_display_t *disp = lv_display_create(WIDTH, HEIGHT);
    lv_display_set_flush_cb(disp, disp_flush);
    lv_display_set_color_format(disp, LV_COLOR_FORMAT_ARGB8888);
    
    static uint8_t buf1[WIDTH * BUF_HEIGHT * BYTE_PER_PIXEL];
    static uint8_t buf2[WIDTH * BUF_HEIGHT * BYTE_PER_PIXEL];
    lv_display_set_buffers(disp, buf1, buf2, 
                          WIDTH * BUF_HEIGHT * BYTE_PER_PIXEL, 
                          LV_DISPLAY_RENDER_MODE_PARTIAL);
}

这里的lv_port_disp_init 函数其实就是 lv_port_disp_template.c 示例中的重定义:
在这里插入图片描述

5. 创建lvgl布局控件

// 创建带布局的UI界面
void create_ui(void) {
    // 获取当前活跃的屏幕
    lv_obj_t *scr = lv_scr_act();
    
    // 创建主容器(使用Flex布局)
    lv_obj_t *cont = lv_obj_create(scr);
    lv_obj_set_size(cont, WIDTH - 40, HEIGHT - 40); // 留出边距
    lv_obj_center(cont);
    
    // 设置Flex布局参数
    lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);  // 垂直排列
    lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_SPACE_EVENLY, 
                         LV_FLEX_ALIGN_CENTER, 
                         LV_FLEX_ALIGN_CENTER);
    
    // 添加标题标签
    lv_obj_t *title = lv_label_create(cont);
    lv_label_set_text(title, "LVGL SDL3 Demo");
    // lv_obj_set_style_text_font(title, &lv_font_montserrat_28, 0);
    lv_obj_set_style_text_color(title, lv_color_hex(0x003a57), 0);

    // 创建按钮容器(水平排列)
    lv_obj_t *btn_cont = lv_obj_create(cont);
    lv_obj_set_size(btn_cont, lv_pct(100), 80);
    lv_obj_set_flex_flow(btn_cont, LV_FLEX_FLOW_ROW);
    lv_obj_set_flex_align(btn_cont, LV_FLEX_ALIGN_SPACE_EVENLY, 
                         LV_FLEX_ALIGN_CENTER, 
                         LV_FLEX_ALIGN_CENTER);
    lv_obj_remove_style_all(btn_cont); // 移除默认样式

    // 添加三个不同样式的按钮
    const char *btns[] = {"sure", "cancl", "more..."};
    for(int i = 0; i < 3; i++) {
        lv_obj_t *btn = lv_button_create(btn_cont);
        lv_obj_set_size(btn, 100, 40);
        
        // 按钮标签
        lv_obj_t *label = lv_label_create(btn);
        lv_label_set_text(label, btns[i]);
        lv_obj_center(label);
        
        // 设置不同颜色样式
        static lv_style_t style_btn;
        lv_style_init(&style_btn);
        lv_style_set_bg_color(&style_btn, lv_color_hex(i == 0 ? 0x00aa00 : 
                                            (i == 1 ? 0xaa0000 : 0x555555)));
        lv_style_set_radius(&style_btn, 8);
        lv_obj_add_style(btn, &style_btn, 0);
    }

    // 添加信息文本区域
    lv_obj_t *info = lv_textarea_create(cont);
    lv_textarea_set_text(info, "init.........................");
    lv_obj_set_size(info, lv_pct(100), 120);
    lv_obj_set_style_border_width(info, 2, 0);
    lv_obj_set_style_border_color(info, lv_color_hex(0xcccccc), 0);
}

6. 主函数

主函数中包含lvgl和sdl 的相关初始化和设置

int main(int argc, char *argv[]) {
initSDL();
    lv_init();
    lv_port_disp_init();

    create_ui();

    while (running) {
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_EVENT_QUIT) running = false;
        }

        lv_timer_handler();
        SDL_RenderClear(renderer);
        SDL_RenderTexture(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);
        
        static Uint32 last = 0;
        Uint32 now = SDL_GetTicks();
        lv_tick_inc(now - last);
        last = now;
        SDL_Delay(1);
    }

    // 释放资源
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

7. 运行测试及完整代码

测试:
在这里插入图片描述
完整代码:

#include "SDL3/SDL.h"
#include "lvgl/lvgl.h"

#define BYTE_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_ARGB8888))
#define WIDTH (600)  // 屏幕宽度
#define HEIGHT (400) // 屏幕高度
#define BUF_HEIGHT 40    // 小行缓冲

static SDL_Window *window;
static SDL_Renderer *renderer;
static SDL_Texture *texture;

static volatile bool running = true;

int initSDL() {
    // 初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        SDL_Log(" SDL init falid : %s", SDL_GetError());
        return -1;
    }

    // 创建窗口
    window = SDL_CreateWindow("SDL3", WIDTH, HEIGHT, SDL_WINDOW_HIGH_PIXEL_DENSITY);

    // // 创建渲染器
    renderer = SDL_CreateRenderer(window, NULL);

    // SDL_CreateWindowAndRenderer("SDL3", HOR, VER, SDL_WINDOW_HIGH_PIXEL_DENSITY, &window, &renderer);

    // 创建纹理
    texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, // 改为流式访问
                                WIDTH, HEIGHT);

    if (!window || !renderer || !texture) {
        SDL_Log("initSDL fail: %s", SDL_GetError());
        SDL_Quit();
        running = false;
        return -1;
    }
    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); // 设置背景为白色
    return 0;
}

void disp_flush(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) {
    SDL_Rect src_rect = {
        .x = area->x1,
        .y = area->y1,
        .w = area->x2 - area->x1 + 1,
        .h = area->y2 - area->y1 + 1
    };

    // 更新纹理的特定区域
    SDL_UpdateTexture(texture, &src_rect, px_map, WIDTH * BYTE_PER_PIXEL);

    // 渲染整个纹理到窗口
    SDL_RenderTexture(renderer, texture, NULL, NULL);
    lv_display_flush_ready(disp);
}

void lv_port_disp_init(void) {
    lv_display_t *disp = lv_display_create(WIDTH, HEIGHT);
    lv_display_set_flush_cb(disp, disp_flush);
    lv_display_set_color_format(disp, LV_COLOR_FORMAT_ARGB8888);
    
    static uint8_t buf1[WIDTH * BUF_HEIGHT * BYTE_PER_PIXEL];
    static uint8_t buf2[WIDTH * BUF_HEIGHT * BYTE_PER_PIXEL];
    lv_display_set_buffers(disp, buf1, buf2, 
                          WIDTH * BUF_HEIGHT * BYTE_PER_PIXEL, 
                          LV_DISPLAY_RENDER_MODE_PARTIAL);
}

// 创建带布局的UI界面
void create_ui(void) {
    // 获取当前活跃的屏幕
    lv_obj_t *scr = lv_scr_act();
    
    // 创建主容器(使用Flex布局)
    lv_obj_t *cont = lv_obj_create(scr);
    lv_obj_set_size(cont, WIDTH - 40, HEIGHT - 40); // 留出边距
    lv_obj_center(cont);
    
    // 设置Flex布局参数
    lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);  // 垂直排列
    lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_SPACE_EVENLY, 
                         LV_FLEX_ALIGN_CENTER, 
                         LV_FLEX_ALIGN_CENTER);
    
    // 添加标题标签
    lv_obj_t *title = lv_label_create(cont);
    lv_label_set_text(title, "LVGL SDL3 Demo");
    // lv_obj_set_style_text_font(title, &lv_font_montserrat_28, 0);
    lv_obj_set_style_text_color(title, lv_color_hex(0x003a57), 0);

    // 创建按钮容器(水平排列)
    lv_obj_t *btn_cont = lv_obj_create(cont);
    lv_obj_set_size(btn_cont, lv_pct(100), 80);
    lv_obj_set_flex_flow(btn_cont, LV_FLEX_FLOW_ROW);
    lv_obj_set_flex_align(btn_cont, LV_FLEX_ALIGN_SPACE_EVENLY, 
                         LV_FLEX_ALIGN_CENTER, 
                         LV_FLEX_ALIGN_CENTER);
    lv_obj_remove_style_all(btn_cont); // 移除默认样式

    // 添加三个不同样式的按钮
    const char *btns[] = {"sure", "cancl", "more..."};
    for(int i = 0; i < 3; i++) {
        lv_obj_t *btn = lv_button_create(btn_cont);
        lv_obj_set_size(btn, 100, 40);
        
        // 按钮标签
        lv_obj_t *label = lv_label_create(btn);
        lv_label_set_text(label, btns[i]);
        lv_obj_center(label);
        
        // 设置不同颜色样式
        static lv_style_t style_btn;
        lv_style_init(&style_btn);
        lv_style_set_bg_color(&style_btn, lv_color_hex(i == 0 ? 0x00aa00 : 
                                            (i == 1 ? 0xaa0000 : 0x555555)));
        lv_style_set_radius(&style_btn, 8);
        lv_obj_add_style(btn, &style_btn, 0);
    }

    // 添加信息文本区域
    lv_obj_t *info = lv_textarea_create(cont);
    lv_textarea_set_text(info, "init.........................");
    lv_obj_set_size(info, lv_pct(100), 120);
    lv_obj_set_style_border_width(info, 2, 0);
    lv_obj_set_style_border_color(info, lv_color_hex(0xcccccc), 0);
}


int main(int argc, char *argv[]) {
initSDL();
    lv_init();
    lv_port_disp_init();

    create_ui();

    while (running) {
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_EVENT_QUIT) running = false;
        }

        lv_timer_handler();
        SDL_RenderClear(renderer);
        SDL_RenderTexture(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);
        
        static Uint32 last = 0;
        Uint32 now = SDL_GetTicks();
        lv_tick_inc(now - last);
        last = now;
        SDL_Delay(1);
    }

    // 释放资源
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

参考: 使用SDL2搭建简易LVGL模拟器

后续将尝试整合lvgl 和 sdl 事件, 感兴趣的可加qq群讨论: 1046502146

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不知所云,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值