@[TOC]
一、介绍
LittlevGL是一个免费的开源图形库,提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素、漂亮的视觉效果和低内存占用。
目前官方的LittleVGL只支持C语言和MicroPython两种开发语言,合宙在保留了官方接口的同时,推出了支持Lua语言的LittleVGL版本,方便开发者使用Lua语言在Air724U系列模块中开发图形界面
二、目的 本文重点介绍了如何用Lua版本的LittleVGL来做UI界面开发。
三、环境准备
1, Air724U开发板
2, LCD显示屏
3, Lua版本的LittleVGL固件
4, Luatools开发工具
四、运行官方示例 官方固件支持图片显示和简单的button控件,没有按键和触摸屏的处理逻辑。采用定时器方式切换界面。交互逻辑用户可以通过驱动按键或者触摸屏自行添加。
core
注意:选择支持蓝牙版本的core固件进行下载,core之间的差异可以参考开源Lua代码地址首页说明
lua demo
2, 显示效果
五、控件使用 5.1 常用控件 目前Lua版本的LittleVGL由于空间有限,并未支持所有控件,已支持的常用控件:button,image button, image, label, page, container, list, checkbox, slider, window, switch, Arc, spinbox, Animations
, 各种控件的使用和参考代码可以参考官方的控件介绍文档。
5.2 利用控件搭建窗口 所有的窗口都是通过控件组成的,这里涉及到如下信息:
控件是窗口的基本组成单元,所以在创建窗口的时候需要确定使用哪些控件。所有控件都是基于lv中的基础类lv_obj
派生而来,所以lv_obj
中的所有接口和方法都可以在各个基本控件中使用
确定好控件后,就需要确认控件在窗口中的具体位置,位置可以通过如下函数来设置
1 2 3 4 lvgl.obj_set_x lvgl.obj_set_y 或者 lvgl.obj_set_pos
样式属性决定了对象的外观形象,但是样式又相对来说是比较麻烦的,因为我们描绘一个对象的外观的维度是非常多的,比如我们可以设置对象的背景,文本样式,填充样式,线条样式等等,不过我们刚开始学习自带的控件样式就足够我们使用了.
5.3 控件对用事件处理 在窗口中组织好控件后,据需要对具体的业务逻辑进行处理。最典型的就是按钮事件,按钮按下后需要启动新的逻辑,画新的窗口或者后台进行相应的业务处理。 一般控件事件可以通过lv.obj_set_event_cb
函数来设置相应事件触发的回调函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function my_event_cb (obj, event) if event == lvgl.EVENT_PRESSED then print ("Pressed\n" ); elseif event == lvgl.EVENT_SHORT_CLICKED then print ("Short clicked\n" ) elseif event == lvgl.EVENT_CLICKED then print ("Clicked\n" ) elseif event == lvgl.EVENT_LONG_PRESSED then print ("Long press\n" ) elseif event == lvgl.EVENT_RELEASED then print ("Released\n" ) end end btn = lv.btn_create(lv.scr_act(), NULL); lv_obj_set_event_cb(btn, my_event_cb); /*Assign an event callback*/
六、LittleVGL编程 6.1 函数接口介绍 lua版本的littlevgl继承了C语言版本的大部分接口,既能满足嵌入式UI界面开发,又能减少内存使用,详细的接口介绍可以参考《官方文档API部分》 ,中文翻译版本LVGL中文手册.pdf ,只要将其中的lv_或者LV_开头
去掉,换成lvgl.开头
就可以直接使用,例如:
1 2 3 4 //button创建c接口 lv_obj_t *lv_btn_create(lv_obj_t *par, constlv_obj_t *copy) //button创建Lua接口 lv_obj_t lvgl.btn_create(par, copy)
以其中按钮创建为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 //C语言 void lv_ex_btn_1(void) { lv_obj_t * label; lv_obj_t * btn1 = lv_btn_create(lv_scr_act(), NULL); lv_obj_set_event_cb(btn1, event_handler); lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 0, -40); label = lv_label_create(btn1, NULL); lv_label_set_text(label, "Button"); lv_obj_t * btn2 = lv_btn_create(lv_scr_act(), NULL); lv_obj_set_event_cb(btn2, event_handler); lv_obj_align(btn2, NULL, LV_ALIGN_CENTER, 0, 40); lv_btn_set_toggle(btn2, true); lv_btn_toggle(btn2); lv_btn_set_fit2(btn2, LV_FIT_NONE, LV_FIT_TIGHT); label = lv_label_create(btn2, NULL); lv_label_set_text(label, "Toggled"); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 --Lua语言 function lv_ex_btn_1() act_src = lvgl.scr_act() btn1 = lv.btn_create(act_src, nil) lvgl.obj_set_event_cb(btn1, event_handler) lvgl.obj_align(btn1, nil, LVGL.ALIGN_CENTER, 0, -40) label = lvgl.label_create(btn1, nil) lvgl.label_set_text(label, "Button") btn2 = lvgl.btn_create(act_src, nil) lvgl.obj_set_event_cb(btn2, event_handler) lvgl.obj_align(btn2, nil, lvgl.ALIGN_CENTER, 0, 40) lvgl.btn_set_toggle(btn2, true) lvgl.btn_toggle(btn2) lvgl.btn_set_fit2(btn2, lvgl.FIT_NONE, lvgl.FIT_TIGHT) label = lvgl.label_create(btn2, nil) lvgl.label_set_text(label, "Toggled") end
6.2 替换字体 待完善
6.3 添加按键处理 littleVGL支持的事件由以下几种:
控件按下、控件拖拽、控件值改变等,这些控件时间可以通过lvgl.obj_set_event_cb
函数设置回调函数来捕获这类事件。
事件名
事件功能
lvgl.EVENT_PRESSED
对象已被按下
lvgl.EVENT_LONG_PRESSED
对象长按后发布该事件
lvgl.EVENT_CLICKED
对象被按下(不管是否长按)
lvgl.EVENT_RELEASED
对象按下后被抬起
…
…
其他事件也可以通过《官方文档event部分》
这类事件是通过键盘、按钮、触控笔等触发。
事件名
事件功能
lvgl.EVENT_DRAG_BEGIN
开始拖拽
lvgl.EVENT_DRAG_END
对象长按后发布该事件
lvgl.EVENT_DRAG_THROW_BEGIN
对象被按下(不管是否长按)
lvgl.EVENT_KEY
对象按下后被抬起
…
…
6.4 触摸屏处理 待完善
七、代码例程 利用Lua Littlevgl实现的例程代码可以通过合宙码云开源平台–Luat_Lua_Air724U 获取。 完整的demo\lvgl
完成了lvgl支持的所有常用控件的列举、通过窗口切换来完成展示。具体代码和效果如下:
注意:因为下方图片通过直接dump内存来显示的,经过工具转换后颜色显示不正常。正常颜色以实际显示效果为准!!!!
7.1 image控件 image空间主要用来存放已经导入lua的图片资源文件,对应代码在demo\lvgl\widget.lua
文件
1 2 3 4 5 6 7 8 9 10 11 12 local function empty () c = lvgl.cont_create(nil , nil ) img = lvgl.img_create(c, nil ) lvgl.img_set_src(img, "/lua/logo.png" ) lvgl.obj_align(img, nil , lvgl.ALIGN_CENTER, 0 , 0 ) lvgl.disp_load_scr(c) end
显示效果如下:
7.2 Canvas控件 Canvas(画布)控件类似于image控件,用户可以在这个控件上画任何内容、包括绘制图片、绘制线条、绘制文字等。lua中用该控件显示了二维码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function create () scr = lvgl.cont_create(nil , nil ) cv = lvgl.canvas_create(scr, nil ) lvgl.canvas_set_buffer(cv, 100 , 100 ) lvgl.obj_align(cv, nil , lvgl.ALIGN_CENTER, 0 , 0 ) layer_id = lvgl.canvas_to_disp_layer(cv) disp.setactlayer(layer_id) width, data = qrencode.encode('http://www.openluat.com' ) l_w, l_h = disp.getlayerinfo() displayWidth = 100 disp.putqrcode(data, width, displayWidth, (l_w-displayWidth)/2 , (l_h-displayWidth)/2 ) disp.update() return scr end
button控件比较好理解,可以相应用户在屏幕上的按下操作,并做出相应动作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function create () scr = lvgl.cont_create(nil , nil ) style = lvgl.style_t() lvgl.style_copy(style, lvgl.style_plain) style.line.color = lvgl.color_hex(0x800000 ) style.line.width = 4 btn = lvgl.btn_create(scr, nil ) btn_label = lvgl.label_create(btn, nil ) lvgl.label_set_text(btn_label, "按钮" ) lvgl.obj_align(btn, nil , lvgl.ALIGN_CENTER, 0 , 40 ) lvgl.obj_set_size(btn, 60 , 60 ) return scr end
7.4 Arc控件(加载器) 加载器用一个圆圈的来表示一个任务的处理进程,处理完成后圆圈便完整显示出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function create () scr = lvgl.cont_create(nil , nil ) style = lvgl.style_t() lvgl.style_copy(style, lvgl.style_plain) style.line.color = lvgl.color_hex(0x800000 ) style.line.width = 4 arc = lvgl.arc_create(scr, nil ) lvgl.arc_set_style(arc, lvgl.ARC_STYLE_MAIN, style) lvgl.arc_set_angles(arc, 180 , 180 ) lvgl.obj_set_size(arc, 40 , 40 ) lvgl.obj_align(arc, nil , lvgl.ALIGN_CENTER, -30 , -30 ) arc_label = lvgl.label_create(scr, nil ) lvgl.label_set_text(arc_label, "加载器" ) lvgl.obj_align(arc_label, arc, lvgl.ALIGN_OUT_RIGHT_MID, 4 , 0 ) sys.timerLoopStart(arc_loader, 100 ) return scr end
7.5 page控件 page控件本身是一个容器,可以设置这个容器的大小,容器内部也可以放置其他的子控件。并且随着page的增大减小,page根据里面的内容来决定是否可以滑动显示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function create () black = lvgl.color_make(0 , 0 , 0 ) white = lvgl.color_make(0xff , 0xff , 0xff ) scr = lvgl.cont_create(nil , nil ) style_sb = lvgl.style_t() style_sb.body.main_color = black style_sb.body.grad_color = black style_sb.body.border.color = white style_sb.body.border.width = 1 style_sb.body.border.opa = lvgl.OPA_70 style_sb.body.radius = lvgl.RADIUS_CIRCLE style_sb.body.opa = lvgl.OPA_60 style_sb.body.padding.right = 3 style_sb.body.padding.bottom = 3 style_sb.body.padding.inner = 8 page = lvgl.page_create(scr, nil ) lvgl.obj_set_size(page, 100 , 150 ) lvgl.obj_align(page, nil , lvgl.ALIGN_CENTER, 0 , 0 ) lvgl.page_set_style(page, lvgl.PAGE_STYLE_SB, style_sb) return scr end
7.6 label控件 标签控件一般用来显示一段文字,也可以显示多行文字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function create () ... label = lvgl.label_create(page, nil ) lvgl.label_set_long_mode(label, lvgl.LABEL_LONG_BREAK) lvgl.obj_set_width(label, lvgl.page_get_fit_width(page)) lvgl.label_set_recolor(label, true ) lvgl.label_set_text(label, [[ Air722UG Air724UG 行1 行2 行3]] ) return scr end
7.7 Slider控件 滑动条类似进度条,但本身滑动条上有一个圈可以根据需要进行拖动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 function create () scr = lvgl.cont_create(nil , nil ) style_bg = lvgl.style_t() style_indic = lvgl.style_t() style_knob = lvgl.style_t() lvgl.style_copy(style_bg, lvgl.style_pretty) style_bg.body.main_color = lvgl.color_hex(0x00ff00 ) style_bg.body.grad_color = lvgl.color_hex(0x000080 ) style_bg.body.radius = lvgl.RADIUS_CIRCLE style_bg.body.border.color = lvgl.color_hex(0xffffff ) lvgl.style_copy(style_indic, lvgl.style_pretty_color) style_indic.body.radius = lvgl.RADIUS_CIRCLE style_indic.body.shadow.width = 8 style_indic.body.shadow.color = style_indic.body.main_color style_indic.body.padding.left = 3 style_indic.body.padding.right = 3 style_indic.body.padding.top = 3 style_indic.body.padding.bottom = 3 lvgl.style_copy(style_knob, lvgl.style_pretty) style_knob.body.radius = lvgl.RADIUS_CIRCLE style_knob.body.opa = lvgl.OPA_70 style_knob.body.padding.top = 10 style_knob.body.padding.bottom = 10 slider = lvgl.slider_create(scr, nil ) lvgl.obj_set_size(slider, 100 , 20 ) lvgl.slider_set_style(slider, lvgl.SLIDER_STYLE_BG, style_bg) lvgl.slider_set_style(slider, lvgl.SLIDER_STYLE_INDIC, style_indic) lvgl.slider_set_style(slider, lvgl.SLIDER_STYLE_KNOB, style_knob) lvgl.obj_align(slider, nil , lvgl.ALIGN_CENTER, 0 , 0 ) label = lvgl.label_create(scr, nil ) lvgl.label_set_text(label, "滑动条" ) lvgl.obj_align(label, slider, lvgl.ALIGN_OUT_BOTTOM_MID, 0 , 0 ) return scr end
7.8 switch控件 开关控件用来表示业务的状态开或者关。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function create () scr = lvgl.cont_create(nil , nil ) ... sw = lvgl.sw_create(scr, nil ) lvgl.obj_align(sw, nil , lvgl.ALIGN_CENTER, 0 , 0 ) lvgl.sw_set_style(sw, lvgl.SW_STYLE_BG, bg_style) lvgl.sw_set_style(sw, lvgl.SW_STYLE_INDIC, indic_style) lvgl.sw_set_style(sw, lvgl.SW_STYLE_KNOB_ON, knob_on_style) lvgl.sw_set_style(sw, lvgl.SW_STYLE_KNOB_OFF, knob_off_style) label = lvgl.label_create(scr, nil ) lvgl.label_set_text(label, "开关" ) lvgl.obj_align(label, sw, lvgl.ALIGN_OUT_BOTTOM_MID, 0 , 2 ) sys.timerStart(sw_toggle, 1000 , true ) return scr end