【LVGL】学习笔记--(2)GUI Guider的使用

基于上一篇【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL,已经成功地移植了LVGL到我们的嵌入式板子上,并配合磁控旋钮编码器(或者诸如触摸屏、按键、键盘等其他输入设备均可),实现了简单界面的显示工作。

这一章将学习用GUI Guider设计界面以实现旋钮控制界面上控件的操作以及进行界面切换,在这个过程中体会GUI Guider的作用

一 GUI Guider简介

GUI Guider是恩智浦提供的用户友好型图形用户界面开发工具,可通过开源LVGL图形库快速开发高品质的显示。GUI Guider的拖放编辑器可以轻松利用LVGL的众多特性,如小部件、动画和样式来创建GUI,而只需少量代码或根本无需任何代码。

特点如下:

  • 支持拖放的所见即所得UI设计;

  • 利用并搜索LVGL的各种小部件,轻松创建GUI应用

  • 自定义并配置小部件属性,可自定义您的设计

  • 轻松添加事件、动作和动画来增强您的应用

  • 导入图像和自定义字体的内置资源管理

  • 为MCUXpresso IDE和IAR Embedded Workbench项目生成应用代码

  • 恩智浦评估工具包可用的模板

  • 集成的演示应用,可帮助您开始设计

  • 在支持的平台上利用PXP和VGLite加速的选项

下载路径:NXP官方下载

二 新建工程

下载安装不赘述,装好之后可以右上角修改为中文。新建工程步骤如下:

  1. 左上角文件-->新建,选择对应的LVGL版本,点击下一步:

【LVGL】学习笔记--(2)GUI Guider的使用_第1张图片
  1. 选择设备模板为PC端仿真器:

【LVGL】学习笔记--(2)GUI Guider的使用_第2张图片
  1. 选择一个应用模板,我这边选择了第一个“按键计数器”:

【LVGL】学习笔记--(2)GUI Guider的使用_第3张图片
  1. 填写工程信息:

【LVGL】学习笔记--(2)GUI Guider的使用_第4张图片
  1. 创建成功:

【LVGL】学习笔记--(2)GUI Guider的使用_第5张图片
  1. 界面的基本操作以及控件的创建等这边不介绍了,全中文而且选项也不多,自己点一点看一下就知道了。

三 界面设计

由于想测试一下界面的切换,所以这边一下创建了三个页面,在其中添加了不同的控件,如下所示:

  1. 界面一screen

其作用是按加、减按钮,文本做对应的数据变化。NEXT按钮添加事件,切换到界面二:

【LVGL】学习笔记--(2)GUI Guider的使用_第6张图片
  1. 界面二screen1

其作用是拖动滑块,文本框做对应的数据变化。BACK/NEXT按钮添加事件,分别切换到界面一/界面三:

【LVGL】学习笔记--(2)GUI Guider的使用_第7张图片
  1. 界面三screen2:

其作用是BACK按钮添加事件,分别切换到界面二:

【LVGL】学习笔记--(2)GUI Guider的使用_第8张图片

完成上述设计之后,点击运行调用模拟器并生成界面文件:

【LVGL】学习笔记--(2)GUI Guider的使用_第9张图片
【LVGL】学习笔记--(2)GUI Guider的使用_第10张图片

四 代码移植

【1】目录结构

GUI Guider经过编译运行之后,生成的代码如下:

  • custom.c为用户自定义API,这个文件的内容事先由用户写进去,不随着工程的编译修改而变化;

  • event_init.c为事件触发API

  • gui_guider.c为界面引导API;

  • setup_scr_screen.c/setup_scr_screen_1.c/setup_scr_screen_2.c为界面的初始化API

  • 界面上用到的字体、图片等资源均在generated文件夹中;

【LVGL】学习笔记--(2)GUI Guider的使用_第11张图片

【2】移植到Keil

  1. 将custom、generated这两个文件夹整体复制到自己的工程目录下

【LVGL】学习笔记--(2)GUI Guider的使用_第12张图片
  1. Keil中创建GUI/LVGL/GEN组,将上面的源文件全部包含进来,包括用到的字体文件、图片文件

【LVGL】学习笔记--(2)GUI Guider的使用_第13张图片

【3】适配修改

我这边用到了外部输入设备磁控旋钮编码器,所以这边需要做两处修改

  • 需要将各个界面中要操作的控件,挂载在一个Group下。我这边有三个界面,所以一共创建了三个Group(groupRect/groupRect1/groupRect2)

  • 由于每个界面对应一个组,所以界面切换过程中,输入设备需要重新绑定Group。以上的控件挂载以及输入设备绑组的操作可以放在初始化函数中

适配界面切换的代码修改如下:

/* 界面一的初始化在setup_scr_screen.c中 */
extern lv_indev_t * indev_encoder;
lv_group_t *groupRect;

void setup_scr_screen(lv_ui *ui){
    //...
    //绑定组1和设备
    groupRect = lv_group_create();  //创建组1
    //挂载组1的控件,包括加减按钮以及指向下一个界面的按钮
    lv_group_add_obj(groupRect,guider_ui.screen_plus);
    lv_group_add_obj(groupRect,guider_ui.screen_minus);
    lv_group_add_obj(groupRect,guider_ui.screen_next);
    //绑定外部设备
    lv_indev_set_group(indev_encoder,groupRect);

    //Init events for screen
    events_init_screen(ui);
}

/* 界面二的初始化在setup_scr_screen_1.c中 */
extern lv_indev_t * indev_encoder;
lv_group_t *groupRect1;

void setup_scr_screen_1(lv_ui *ui){
    //...
    //绑定组2和设备
    groupRect1 = lv_group_create();  //创建组2
    //挂载组2的控件,包括指向前一个/下一个界面的按钮和滑块
    lv_group_add_obj(groupRect1,guider_ui.screen_1_back);
    lv_group_add_obj(groupRect1,guider_ui.screen_1_slider_1);
    lv_group_add_obj(groupRect1,guider_ui.screen_1_next_1);
    //绑定外部设备
    lv_indev_set_group(indev_encoder,groupRect1);

    //Init events for screen
    events_init_screen_1(ui);
}

/* 界面三的初始化在setup_scr_screen_2.c中 */
extern lv_indev_t * indev_encoder;
lv_group_t *groupRect2;

void setup_scr_screen_2(lv_ui *ui){
    //...
    //绑定组3和设备
    groupRect2 = lv_group_create();  //创建组3
    //挂载组3的控件,包括指向前一个界面的按钮以及列表List控件的各个条目items
    lv_group_add_obj(groupRect2,guider_ui.screen_2_btn_1);
    lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item0);
    lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item1);
    lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item3);
    lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item4);
    lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item5);
    lv_group_add_obj(groupRect2,guider_ui.screen_2_list_1_item6);
    //绑定外部设备
    lv_indev_set_group(indev_encoder,groupRect2);

    //Init events for screen
    events_init_screen_2(ui);
}

【4】调用引导

在主任务中包含头文件并调用引导函数:

#include "gui_guider.h"
#include "events_init.h"
#include "custom.h"  //用到用户自定义的API才需要调用
lv_ui guider_ui;

void GUI_Task(void)
{
    //LVGL初始化
    lv_init();
    //显示器初始化
    lv_port_disp_init();
    //外部输入初始化
    lv_port_indev_init();
    
    //设计小部件的ui布局
    setup_ui(&guider_ui);
    //设置小部件的事件
    events_init(&guider_ui);
    //运行自定义的程序(用到用户自定义的API才需要调用)
    //custom_init(&guider_ui);

    while(1)
    {
        knob_now = knobPosNow();  //确定旋钮当前位置
        knob_state_now = Knob_State_Entry(&knob_old, &knob_now, knob_state_old);  //确定旋钮当前状态
        if(KNOB_ESCAPE == knob_state_now)
        {
            knob_state_old = knob_state_now;
        }
        else
        {
            knob_old = knob_now;
            knob_state_old = knob_state_now;
        }
        lv_task_handler();
        os_dly_wait(5);
    }
}

【5】测试效果

测试效果如下:

五 用户自定义API

用户自定义的API在custom.c中。

【1】自定义API

新加了一个界面,其初始化和事件声明均在custom_init中(因为只是简单地示例怎么用custom.c,这边就不绑定外部设备了):

/**
 * @file custom.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include 
#include "lvgl.h"
#include "custom.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/

/**********************
 *  STATIC VARIABLES
**********************/
static void event_cb(lv_event_t * e)//事件声明
{
    LV_LOG_USER("Clicked");

    static uint32_t cnt = 1;
    lv_obj_t * btn = lv_event_get_target(e);
    lv_obj_t * label = lv_obj_get_child(btn, 0);
    lv_label_set_text_fmt(label, "%"LV_PRIu32, cnt);
    cnt++;
}

/**
 * Create a demo application
 */
void lv_example_event_1(void)  //创建一个带标签的按钮
{
    lv_obj_t * btn = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn, 100, 50);
    lv_obj_center(btn);
    lv_obj_add_event_cb(btn, event_cb, LV_EVENT_CLICKED, NULL);//把刚才的回调函数添加到按钮上

    lv_obj_t * label = lv_label_create(btn);
    lv_label_set_text(label, "Click me!");
    lv_obj_center(label);
}

void custom_init(lv_ui *ui)
{
    /* Add your codes here */
    lv_example_event_1();
}

【2】调用引导

在主任务中调用custom_init(&guider_ui)即可。

【3】测试效果

GUI Guider模拟器中运行效果:

【LVGL】学习笔记--(2)GUI Guider的使用_第14张图片

实际运行效果:

【LVGL】学习笔记--(2)GUI Guider的使用_第15张图片

注1:因为没有绑定外部设备,且没有注册到界面一里面去,所以不能实际操作,同时界面一切换就没了。更多的用法有待继续发掘;

注2:实际屏幕出来的颜色,有些与模拟器存在差别,原因在于实际的RGB颜色到我显示屏上输出会反过来,变成BGR,例如需要#44CEF6的蓝色,实际出来#F6CE44的黄色

【LVGL】学习笔记--(2)GUI Guider的使用_第16张图片

解决办法是,对 lv_color.h 中定义的取色函数 lv_color_make 进行修改即可

//原先
static inline lv_color_t lv_color_make(uint8_t r, uint8_t g, uint8_t b)
{
    return _LV_COLOR_MAKE_TYPE_HELPER LV_COLOR_MAKE(r, g, b);
}

//修改
static inline lv_color_t lv_color_make(uint8_t r, uint8_t g, uint8_t b)
{
    return _LV_COLOR_MAKE_TYPE_HELPER LV_COLOR_MAKE(b, g, r);
}

六 附录

本文涉及的GUI Guider例程文件已经整理打包好:

GUI Guider使用例程(应用LVGL的三个界面切换)

你可能感兴趣的:(嵌入式,嵌入式硬件,C语言,stm32,LVGL,GUI,Guider)