LVGL 模拟器
安装设置
Ubuntu24.04 VSCode
源码地址:源码地址
我们使用v8版本,拉取源码
git clone --recursive -b release/v8 --single-branch https://github.com/lvgl/lv_port_pc_vscode
安装编译环境和sdl
sudo apt-get update && sudo apt-get install -y build-essential libsdl2-dev
使用vscode开打这个目录, 注意不要直接打开目录,要打开workspace
源码配置
修改Makefile 将LV_DRIVER由原来的X11改成SDL2
#LV_DRIVER := X11
LV_DRIVER := SDL2
编译运行
按F5直接编译并运行,或者使用make来编译
修改模拟屏幕的分辨率
lv_drv_conf.h 98 和 99行的 SDL_HOR_RES
SDL_VER_RES
注意: 修改完后,需要make clean
彻底清除后再编译。
编写自己的项目代码
以简单计算器为例
首先,在项目目录下新建一个calc文件夹,用于存放我们的h和c文件。 在文件夹下建立lv_demo_calc.h和lv_demo_calc.c,内容如下
lv_demo_calc.h:
#ifndef LV_DEMO_CALC_H
#define LV_DEMO_CALC_H
#ifdef __cplusplus
extern "C" {
#endif
void lv_demo_calc(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif // LV_DEMO_CALC_H
lv_demo_calc.c
#include "lvgl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CALC_BTN_ROW 5
#define CALC_BTN_COL 4
static lv_obj_t *ta; // 显示
static char exp_buf[64];
static const char *btn_map[CALC_BTN_ROW][CALC_BTN_COL] = {
{"7", "8", "9", "/"},
{"4", "5", "6", "*"},
{"1", "2", "3", "-"},
{"0", ".", "=", "+"},
{"C", NULL, NULL, NULL},
};
typedef struct {
double last;
double curr;
char op;
bool op_set;
bool new_input;
} calc_ctx_t;
static calc_ctx_t ctx;
static void update_text_area() {
lv_label_set_text(ta, exp_buf);
}
// 按钮事件回调
static void btn_event_cb(lv_event_t *e) {
lv_obj_t *btn = lv_event_get_target(e);
lv_obj_t *label = lv_obj_get_child(btn, 0);
const char *txt = lv_label_get_text(label);
if (strcmp(txt, "C") == 0) {
memset(exp_buf, 0, sizeof(exp_buf));
ctx.last = 0;
ctx.curr = 0;
ctx.op = 0;
ctx.op_set = false;
ctx.new_input = false;
update_text_area();
return;
}
if (strcmp(txt, "=") == 0) {
if(ctx.op_set) {
double res = 0;
switch(ctx.op) {
case '+': res = ctx.last + ctx.curr; break;
case '-': res = ctx.last - ctx.curr; break;
case '*': res = ctx.last * ctx.curr; break;
case '/': res = (ctx.curr != 0) ? ctx.last / ctx.curr : 0; break;
default: res = ctx.curr; break;
}
snprintf(exp_buf, sizeof(exp_buf), "%.10g", res);
ctx.last = res;
ctx.op = 0;
ctx.op_set = false;
ctx.new_input = true;
update_text_area();
}
return;
}
// 运算符
if(strcmp(txt, "+") == 0 || strcmp(txt, "-") == 0 || strcmp(txt, "*") == 0 || strcmp(txt, "/") == 0) {
if(!ctx.op_set) {
ctx.last = strtod(exp_buf, NULL);
ctx.op = txt[0];
ctx.op_set = true;
ctx.new_input = true;
} else {
// 连续输入运算符
double res = 0;
switch(ctx.op) {
case '+': res = ctx.last + ctx.curr; break;
case '-': res = ctx.last - ctx.curr; break;
case '*': res = ctx.last * ctx.curr; break;
case '/': res = (ctx.curr != 0)? ctx.last / ctx.curr : 0; break;
}
ctx.last = res;
ctx.op = txt[0];
ctx.op_set = true;
snprintf(exp_buf, sizeof(exp_buf), "%.10g", ctx.last);
ctx.new_input = true;
update_text_area();
}
return;
}
// 数字和点
if(strlen(txt) == 1 && ((txt[0]>='0' && txt[0]<='9') || txt[0]=='.')) {
if(ctx.new_input) {
strncpy(exp_buf, txt, sizeof(exp_buf)-1);
exp_buf[sizeof(exp_buf)-1] = '\0';
ctx.new_input = false;
} else {
if(strlen(exp_buf) < sizeof(exp_buf)-1) {
strncat(exp_buf, txt, 1);
exp_buf[sizeof(exp_buf)-1] = '\0';
}
}
ctx.curr = strtod(exp_buf, NULL);
update_text_area();
return;
}
}
void lv_demo_calc(void)
{
// 主容器
lv_obj_t *cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 800, 480);
lv_obj_center(cont);
lv_obj_set_style_pad_all(cont, 0, 0);
// 只读文本“区域”: 替换为label
ta = lv_label_create(cont);
lv_obj_set_size(ta, 770, 60);
lv_obj_set_pos(ta, 15, 15);
lv_label_set_text(ta, "");
lv_obj_set_style_text_font(ta, &lv_font_montserrat_28, 0);
lv_obj_set_style_text_align(ta, LV_TEXT_ALIGN_RIGHT, 0);
// 按钮区,每个按钮宽170高62
int start_x = 15, start_y = 90;
int btn_w = 170, btn_h = 62, btn_space = 6;
for(int r = 0; r < CALC_BTN_ROW; ++r) {
for(int c = 0; c < CALC_BTN_COL; ++c) {
const char *txt = btn_map[r][c];
if(txt == NULL) continue;
lv_obj_t *btn = lv_btn_create(cont);
lv_obj_set_size(btn, btn_w, btn_h);
lv_obj_set_pos(btn, start_x + c*(btn_w+btn_space), start_y + r*(btn_h+btn_space));
lv_obj_t *label = lv_label_create(btn);
lv_label_set_text(label, txt);
lv_obj_center(label);
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL);
}
}
memset(exp_buf, 0, sizeof(exp_buf));
memset(&ctx, 0, sizeof(ctx));
update_text_area();
}
在main.c中 #include "calc/lv_demo_calc.h"
main函数中,原来的lv_demo_widgets();
注释掉,加上计算器的方法 lv_demo_calc();
编译运行