还在用C编写LVGL上的画面,何不试试Python? (2)
在上一篇中,小编为大家简单介绍了LVGL库,并且介绍了如何实现lvgl和MicroPython的绑定,使得lvgl以MicroPython模块的形式供用户通过Python进行调用,方便开发。
输入/输出设备驱动添加
# 所编写的模块驱动
import lvgl_helper
# 注册显示驱动.
disp_buf1 = lv.disp_buf_t()
buf1_1 = bytes(480*10) # 声明lvgl绘制GUI的buffer,lvgl支持1-2个
# buffer
disp_buf1.init(buf1_1, None, len(buf1_1)//4)
disp_drv = lv.disp_drv_t()
disp_drv.init()
disp_drv.buffer = disp_buf1
disp_drv.flush_cb = lvgl_helper.flush # 注册显示回调函数
disp_drv.hor_res = 480
disp_drv.ver_res = 320
disp_drv.register()
# 注册输入驱动
indev_drv = lv.indev_drv_t()
indev_drv.init()
indev_drv.type = lv.INDEV_TYPE.POINTER
indev_drv.read_cb = lvgl_helper.capture # 注册输入回调函数
indev_drv.register()
这里,我们定义了一个叫做lvgl_helper的模块,其中包括一个叫做flush的函数,负责将lvgl绘制好的GUI刷新到显示设备,另一个函数叫做capture,负责处理输入请求,获取用户输入。
接下来,让我们看看这两个函数是怎么实现的。
首先是lvgl_helper.flush函数,具有三个参数,作用就是将lvgl绘制的目标区域刷新到显示设备:
STATIC mp_obj_t mp_flush(mp_obj_t disp_drv, mp_obj_t area, mp_obj_t color){// 显示设备指针lv_disp_drv_t *disp_ptr = GET_PTR_FROM_OBJ(lv_disp_drv_t, disp_drv);// 待刷新区域lv_area_t *area_ptr = GET_PTR_FROM_OBJ(lv_area_t, area);// 待刷新目标地址指针lv_color_t *color_ptr = GET_PTR_FROM_OBJ(lv_color_t, color);// 获取刷新区域宽和高uint16_t w = lv_area_get_width(area_ptr);uint16_t h = lv_area_get_height(area_ptr);// 真正的刷新函数,根据不同硬件定制化实现Update_FrameBuffer((void*)color_ptr, w, h, COLOR_DEPTH, NULL);// 很重要,在刷新完成后,需要通知lvgl,刷新完毕,可以继续绘制,否则会一直阻塞 // 直到刷新完毕lv_disp_flush_ready(disp_ptr);return mp_const_none;}MP_DEFINE_CONST_FUN_OBJ_3(mp_flush_obj, mp_flush);
与之对应的输入函数,看似简单一点,只有2个参数,其目的就是获取屏幕触摸坐标:
STATIC mp_obj_t mp_capture(mp_obj_t indev_drv, mp_obj_t data){ // 输入设备指针
lv_indev_drv_t *indev_ptr = GET_PTR_FROM_OBJ(lv_indev_drv_t, indev_drv);
// 存储获取的触摸位置坐标(x,y)
lv_indev_data_t* data_ptr = GET_PTR_FROM_OBJ(lv_indev_data_t, data);
// 触摸屏驱动,需要自行实现
DEMO_ReadTouch(indev_ptr, data_ptr, resolution.w, resolution.h);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_capture_obj, mp_capture);
有了显示和输入设备的驱动,就可以算的上万事具备了,不过,东风还没来。
lvgl规定,画面的刷新以及响应输入设备,是通过周期性的调用lv.task_handler()函数实现的,同时需要通过lv.tick_inc(x)函数提供内部时钟。而对于MicroPython,函数的周期性调用有点特殊,是通过周期性的调用mp_sched_schedule函数来实现的。
为了做到周期性调用这一硬性规定,推荐的做法是实现一个timer,软件/硬件的都可以,但是硬件时钟当然最好,并将周期函数以callback的形式注册到timer中:
def timer_callback(self): lv.tick_inc(10) lv.task_handler()timer.init(50) # 刷新时间可以自行调整timer.callback(timer_callback)
这样,一切就都准备就绪了,让我们来搭建一个简单的界面玩一下。
实战操练与效果展示
这次的小demo包括:按钮,滑动条,键盘,文本框以及一个图片控件。
先看下实际效果:
是不是界面很熟悉,是的,小编前面说过了,MicroPython环境依托于openART软件包,因此,我们可以使用openMV IDE进行代码的编写和下载,并通过预览窗口进行GUI预览。
下面逐段说明一下控件所对应的代码实现:
0) 初始化:
import lv
lv.init()
scr = lv.obj() # declare the screen to show
btn = lv.btn(lv.scr_act())# 对齐属性以及位置坐标btn.align(lv.scr_act(), lv.ALIGN.IN_BOTTOM_LEFT, 10, -20)btn.toggle() # 翻转显示,蓝底白字/白底蓝字label = lv.label(btn) # 控件名字label.set_text('start')
2) 滑动条:
slider = lv.slider(lv.scr_act())
slider.align(lv.scr_act(), lv.ALIGN.OUT_RIGHT_TOP, -50, -10)
# 滑动条宽和高
slider.set_width(10)
slider.set_height(300)
# 滑动条范围
slider.set_range(10, 200)
# 滑动条初始值
slider.set_value(100, 0)
3) 键盘:
keyboard = lv.keyboard(lv.scr_act())# 数字键盘# keyboard.set_mode(keyboard.MODE.NUM)# 大写字母键盘# keyboard.set_mode(keyboard.MODE.TEXT_UPPER)# 小写字母键盘# keyboard.set_mode(keyboard.MODE.TEXT_LOWER)# 特殊符号键盘# keyboard.set_mode(keyboard.MODE.SPECIAL)keyboard.align(lv.scr_act(), lv.ALIGN.IN_TOP_LEFT, 0, 0)
4) 文本框:
text = lv.textarea(lv.scr_act())
text.align(lv.scr_act(), lv.ALIGN.IN_BOTTOM_LEFT, 0, 0)
# 设置控件为可拖拽属性
text.drag(True)
5) 图片:
# 读取图片数据img_data = open('/sd/blue_flower_16.txt').read()img = lv.img(lv.scr_act())img.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)# 设置图像属性img_dsc = lv.img_dsc_t( { 'header': {'always_zero': 0, 'w': 100, 'h': 75, 'cf': lv.img.CF.TRUE_COLOR}, 'data_size': len(img_data), 'data': img_data, })img.set_src(img_dsc)
尽管是几个简单的控件的使用,验证了我们的带MicroPython绑定的lvgl已经成功移植到了我们的板子上。
相信大家看完之后,已经跃跃欲试了,那就开始动手吧!