LVGL Canvas画布实战:5分钟教你制作一个可交互的简易绘图板

张开发
2026/5/11 12:43:50 15 分钟阅读

分享文章

LVGL Canvas画布实战:5分钟教你制作一个可交互的简易绘图板
LVGL Canvas画布实战5分钟教你制作一个可交互的简易绘图板在嵌入式GUI开发领域LVGL因其轻量级和高度可定制性成为众多开发者的首选。而Canvas画布控件作为其核心组件之一能够实现从简单图形绘制到复杂交互界面的各种功能。今天我们就来探索如何利用LVGL Canvas快速搭建一个简易的触摸绘图板让你在5分钟内实现手指或触控笔的实时绘图体验。这个项目特别适合对GUI交互开发感兴趣的初学者和创客。通过这个实践你不仅能掌握Canvas的基本用法还能深入理解LVGL的事件处理机制。我们将从零开始一步步构建这个交互式应用涵盖从缓冲区设置、坐标映射到触摸事件处理的完整流程。1. 环境准备与基础配置在开始之前确保你已经搭建好LVGL的开发环境。这里我们假设你使用的是PlatformIOArduino的开发方式但原理同样适用于其他平台。首先我们需要创建一个足够大的缓冲区来存储Canvas的内容。这个缓冲区的大小直接决定了画布的分辨率和内存占用#define CANVAS_WIDTH 320 #define CANVAS_HEIGHT 240 static lv_color_t canvas_buffer[CANVAS_WIDTH * CANVAS_HEIGHT];接下来初始化Canvas对象并设置其基本属性lv_obj_t * canvas lv_canvas_create(lv_scr_act(), NULL); lv_canvas_set_buffer(canvas, canvas_buffer, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR); lv_obj_set_pos(canvas, 0, 0); lv_obj_set_size(canvas, CANVAS_WIDTH, CANVAS_HEIGHT);提示缓冲区大小应根据你的硬件性能合理设置。对于内存受限的设备可以考虑降低分辨率或使用索引颜色模式。2. 实现基本绘图功能Canvas提供了丰富的绘图API我们先实现最基本的画线功能。首先定义一个结构体来保存绘图状态typedef struct { lv_point_t last_point; bool is_drawing; lv_color_t pen_color; uint8_t pen_width; } drawing_state_t; static drawing_state_t draw_state { .pen_color LV_COLOR_RED, .pen_width 3 };然后实现画线函数它将在两点之间绘制一条线段void draw_line(lv_obj_t * canvas, lv_point_t * points, uint16_t point_cnt) { lv_draw_line_dsc_t line_dsc; lv_draw_line_dsc_init(line_dsc); line_dsc.color draw_state.pen_color; line_dsc.width draw_state.pen_width; line_dsc.round_end 1; lv_canvas_draw_line(canvas, points, point_cnt, line_dsc); }3. 处理触摸事件LVGL的事件系统是我们实现交互功能的关键。我们需要为Canvas添加触摸事件处理函数static void event_handler(lv_obj_t * obj, lv_event_t event) { if(event LV_EVENT_PRESSED) { draw_state.is_drawing true; lv_indev_get_point(lv_indev_get_act(), draw_state.last_point); } else if(event LV_EVENT_PRESSING) { lv_point_t current_point; lv_indev_get_point(lv_indev_get_act(), current_point); lv_point_t points[2] {draw_state.last_point, current_point}; draw_line(obj, points, 2); draw_state.last_point current_point; } else if(event LV_EVENT_RELEASED) { draw_state.is_drawing false; } } lv_obj_set_event_cb(canvas, event_handler);这段代码实现了按下时开始绘制移动时连续画线释放时结束绘制4. 增强功能与优化基本的绘图功能已经实现现在我们来添加一些增强功能提升用户体验。4.1 颜色选择器添加一个简单的颜色选择面板lv_obj_t * btn_red lv_btn_create(lv_scr_act(), NULL); lv_obj_set_pos(btn_red, 10, CANVAS_HEIGHT 10); lv_obj_set_size(btn_red, 40, 40); lv_obj_set_style_local_bg_color(btn_red, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); static void color_btn_event(lv_obj_t * obj, lv_event_t event) { if(event LV_EVENT_CLICKED) { draw_state.pen_color lv_obj_get_style_bg_color(obj, LV_BTN_PART_MAIN); } } lv_obj_set_event_cb(btn_red, color_btn_event);4.2 清空画布功能添加一个清空按钮lv_obj_t * btn_clear lv_btn_create(lv_scr_act(), NULL); lv_obj_set_pos(btn_clear, 60, CANVAS_HEIGHT 10); lv_obj_set_size(btn_clear, 80, 40); lv_obj_t * label lv_label_create(btn_clear, NULL); lv_label_set_text(label, Clear); lv_obj_set_event_cb(btn_clear, [](lv_obj_t * obj, lv_event_t event) { if(event LV_EVENT_CLICKED) { lv_canvas_fill_bg(canvas, LV_COLOR_WHITE, LV_OPA_COVER); } });4.3 笔触大小调整添加滑块控制笔触大小lv_obj_t * slider lv_slider_create(lv_scr_act(), NULL); lv_obj_set_pos(slider, 150, CANVAS_HEIGHT 10); lv_obj_set_size(slider, 150, 20); lv_slider_set_range(slider, 1, 20); lv_slider_set_value(slider, draw_state.pen_width, LV_ANIM_OFF); lv_obj_set_event_cb(slider, [](lv_obj_t * obj, lv_event_t event) { if(event LV_EVENT_VALUE_CHANGED) { draw_state.pen_width lv_slider_get_value(obj); } });5. 性能优化技巧当绘图区域较大时频繁刷新可能导致性能问题。以下是几个优化建议局部刷新只刷新发生变化的部分区域lv_obj_invalidate_area(canvas, invalid_area);双缓冲技术使用两个缓冲区交替绘制static lv_color_t canvas_buffer2[CANVAS_WIDTH * CANVAS_HEIGHT];降低采样率对于连续绘制可以适当降低采样点数量使用DMA加速如果硬件支持利用DMA传输图像数据在实际项目中我发现最影响性能的往往是内存访问速度。对于STM32等MCU将Canvas缓冲区放在DTCM或SRAM中可以显著提升绘制速度。另外合理设置LVGL的刷新周期也能平衡性能与流畅度。

更多文章