嵌入式UI开发-lvgl+wsl2+vscode系列:2、label(标签)+button(按钮)+slider(滑块)控件熟悉及其示例demo运行

文章目录

    • 一、前言
    • 二、常见控件示例demo模拟环境运行及接口熟悉
      • (重要)如何修改示例main函数测试各种示例
      • 1、label示例
        • 1.1、label示例1(标签基础示例)
        • 1.2、label示例2(标签带阴影效果)
        • 1.3、label示例3(标签字体设置)
        • 1.4、label示例4(目前未完成)
        • 1.5、label示例5(标签内容滚动动画效果)
      • 2、button示例
        • 2.1、button示例1(基础按钮和切换按钮)
        • 2.2、button示例2(按钮阴影和按钮点击后样式变化)
        • 2.3、button示例3(按钮样式过渡动画效果)
      • 3、slider示例
        • 3.1、slider示例1(基础滑块)
        • 3.2、slider示例2(设置滑块样式)
        • 3.3、slider示例3(滑块值样式设置及显示)
        • 3.4、slider示例4(滑块方向相反)
    • 三、最后

一、前言

上节我们主要了解了lvgl以及在Windows上搭建基于wsl2和vscode的lvgl模拟运行环境,其demo程序已经成功运行起来,接下来我们根据其框架将lvgl的一些常用控件demo和示例提取出来在模拟环境下都跑一跑,熟悉一下对应的接口和比较常用的label、button、slider三个控件。

二、常见控件示例demo模拟环境运行及接口熟悉

如果lv_port_pc_vscode相关内容无法修改,则很可能是目录和文件权限不对,使用了root用户进行下载处理,这时只需要修改权限即可:

sudo chown user lv_port_pc_vscode/ -R
sudo chgrp user lv_port_pc_vscode/ -R
//user就是你当前使用的用户,可以使用ls -alh查看文件夹权限

(重要)如何修改示例main函数测试各种示例

备份原有的main.c,然后修改main.c,将其原来lv_demo_widgets();修改为label相关的函数,主要是lvgl/examples/widgets/label/下的label的示例:


/**
 * @file main
 *
 */

/*********************
 *      INCLUDES
 *********************/
#define _DEFAULT_SOURCE /* needed for usleep() */
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "lvgl/lvgl.h"
#include "lvgl/examples/lv_examples.h"
#include "lvgl/demos/lv_demos.h"

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

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

/**********************
 *  STATIC PROTOTYPES
 **********************/
static lv_display_t * hal_init(int32_t w, int32_t h);

/**********************
 *  STATIC VARIABLES
 **********************/

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

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

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

/**********************
 *      VARIABLES
 **********************/

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

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

int main(int argc, char **argv)
{
  (void)argc; /*Unused*/
  (void)argv; /*Unused*/

  /*初始化LVGL*/
  lv_init();

  /*初始化硬件抽象层 (显示屏, 输入设备, 滴答设备) */
  hal_init(480, 272);

  lv_example_label_1();
  //lv_example_label_2();
  //lv_example_label_3();
  //lv_example_label_4();
  //lv_example_label_5();

  while(1) {
    /* 定期调用 lv_task 回掉.
     * 它也可以在定时器中断或操作系统任务中完成 */
    lv_timer_handler();
    usleep(5 * 1000);
  }

  return 0;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/**
 * 初始化 LVGL 图形的硬件抽象层 (HAL) 库
 */
static lv_display_t * hal_init(int32_t w, int32_t h)
{
    //创建默认group
  lv_group_set_default(lv_group_create());

    //创建显示窗口
  lv_display_t * disp = lv_sdl_window_create(w, h);

    //创建鼠标
  lv_indev_t * mouse = lv_sdl_mouse_create();
  lv_indev_set_group(mouse, lv_group_get_default());
  lv_indev_set_display(mouse, disp);
  lv_display_set_default(disp);

    //声明图像文件
  LV_IMAGE_DECLARE(mouse_cursor_icon);
  lv_obj_t * cursor_obj;
    //为光标创建图像对象
  cursor_obj = lv_image_create(lv_screen_active());
    //设置源图像
  lv_image_set_src(cursor_obj, &mouse_cursor_icon);
    //将图像对象连接到驱动程序
  lv_indev_set_cursor(mouse, cursor_obj);

    //创建鼠标滚轮并绑定
  lv_indev_t * mousewheel = lv_sdl_mousewheel_create();
  lv_indev_set_display(mousewheel, disp);
  lv_indev_set_group(mousewheel, lv_group_get_default());

    //创建键盘
  lv_indev_t * kb = lv_sdl_keyboard_create();
  lv_indev_set_display(kb, disp);
  lv_indev_set_group(kb, lv_group_get_default());

  return disp;
}

之后在之前的build目录下重新make后运行main程序即可:

cd lv_port_pc_vscode/build
make
../bin/main

1、label示例

1.1、label示例1(标签基础示例)
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES

/**
 * 显示换行、重新着色、行对齐和文本滚动
 */
void lv_example_label_1(void)
{
    lv_obj_t * label1 = lv_label_create(lv_screen_active());
    lv_label_set_long_mode(label1, LV_LABEL_LONG_WRAP);     /*长行换行*/
    lv_label_set_text(label1, "Recolor is not supported for v9 now.");
    lv_obj_set_width(label1, 150);  /*设置较小的宽度以使线条换行*/
    lv_obj_set_style_text_align(label1, LV_TEXT_ALIGN_CENTER, 0);
    lv_obj_align(label1, LV_ALIGN_CENTER, 0, -40);

    lv_obj_t * label2 = lv_label_create(lv_screen_active());
    lv_label_set_long_mode(label2, LV_LABEL_LONG_SCROLL_CIRCULAR);     /*循环滚动*/
    lv_obj_set_width(label2, 150);
    lv_label_set_text(label2, "It is a circularly scrolling text. ");
    lv_obj_align(label2, LV_ALIGN_CENTER, 0, 40);
}

#endif

image.png
展示了:

  • 静态的切换长内容的label,设置更小的行宽度以及显示位置、设置内容等基本的方法;
  • 滚动显示内容的label。
1.2、label示例2(标签带阴影效果)
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES

/**
 * 创建假文本阴影
 */
void lv_example_label_2(void)
{
    /*创建阴影样式*/
    static lv_style_t style_shadow;
    lv_style_init(&style_shadow);
    lv_style_set_text_opa(&style_shadow, LV_OPA_30);
    lv_style_set_text_color(&style_shadow, lv_color_black());

    /*首先为阴影创建一个标签(在背景中)*/
    lv_obj_t * shadow_label = lv_label_create(lv_screen_active());
    lv_obj_add_style(shadow_label, &style_shadow, 0);

    /*创建主标签*/
    lv_obj_t * main_label = lv_label_create(lv_screen_active());
    lv_label_set_text(main_label, "A simple method to create\n"
                      "shadows on a text.\n"
                      "It even works with\n\n"
                      "newlines     and spaces.");

    /*为阴影标签设置相同的文本*/
    lv_label_set_text(shadow_label, lv_label_get_text(main_label));

    /*定位主标签*/
    lv_obj_align(main_label, LV_ALIGN_CENTER, 0, 0);

    /*将第二个标签向右下方移动 2 个像素*/
    lv_obj_align_to(shadow_label, main_label, LV_ALIGN_TOP_LEFT, 2, 2);
}

#endif

image.png
展示:

  • 带阴影的label,实际上是两个label,一个label为主,用于显示内容,一个label专门用来作为背景稍微偏移一下实现阴影效果,组合起来就是带有阴影样式的label
1.3、label示例3(标签字体设置)
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES && LV_FONT_DEJAVU_16_PERSIAN_HEBREW && LV_FONT_SIMSUN_16_CJK && LV_USE_BIDI

/**
 * 显示混合 LTR、RTL 和中文标签
 */
void lv_example_label_3(void)
{
    //LTR标签(左对齐)
    lv_obj_t * ltr_label = lv_label_create(lv_screen_active());
    lv_label_set_text(ltr_label, "In modern terminology, a microcontroller is similar to a system on a chip (SoC).");
    lv_obj_set_style_text_font(ltr_label, &lv_font_montserrat_16, 0);
    lv_obj_set_width(ltr_label, 310);
    lv_obj_align(ltr_label, LV_ALIGN_TOP_LEFT, 5, 5);

    //RTL标签(右对齐)
    lv_obj_t * rtl_label = lv_label_create(lv_screen_active());
    lv_label_set_text(rtl_label,
                      "מעבד, או בשמו המלא יחידת עיבוד מרכזית (באנגלית: CPU - Central Processing Unit).");
    lv_obj_set_style_base_dir(rtl_label, LV_BASE_DIR_RTL, 0);
    lv_obj_set_style_text_font(rtl_label, &lv_font_dejavu_16_persian_hebrew, 0);
    lv_obj_set_width(rtl_label, 310);
    lv_obj_align(rtl_label, LV_ALIGN_LEFT_MID, 5, 0);

    //中文标签
    lv_obj_t * cz_label = lv_label_create(lv_screen_active());
    lv_label_set_text(cz_label,
                      "嵌入式系统(Embedded System),\n是一种嵌入机械或电气系统内部、具有专一功能和实时计算性能的计算机系统。");
    lv_obj_set_style_text_font(cz_label, &lv_font_simsun_16_cjk, 0);
    lv_obj_set_width(cz_label, 310);
    lv_obj_align(cz_label, LV_ALIGN_BOTTOM_LEFT, 5, -5);
}

#endif

这里有一些宏默认是0,需要跳转到lv_conf.h中去设置1,其中lv_obj_set_style_text_font这里我设置为了目前的lv_font_montserrat_16,但是项目默认使用的字体是lv_font_montserrat_14,所以要么把这里改为lv_font_montserrat_14,要么就在lv_conf.h中修改:

#define LV_FONT_DEFAULT &lv_font_montserrat_16

#define LV_FONT_MONTSERRAT_14 0
#define LV_FONT_MONTSERRAT_16 1

之后重新make后运行main程序:
image.png
所以这里label主要展示:

  • 设置label文字内容以及设置文字不同字体
  • 设置内容对齐方式
1.4、label示例4(目前未完成)
#include "../../lv_examples.h"
//TODO
#if LV_USE_LABEL && LV_USE_CANVAS && LV_BUILD_EXAMPLES && LV_DRAW_SW_COMPLEX && 0

#define MASK_WIDTH 100
#define MASK_HEIGHT 45

static void add_mask_event_cb(lv_event_t * e)
{
    static lv_draw_mask_map_param_t m;
    static int16_t mask_id;

    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t * obj = lv_event_get_target(e);
    lv_opa_t * mask_map = lv_event_get_user_data(e);
    if(code == LV_EVENT_COVER_CHECK) {
        lv_event_set_cover_res(e, LV_COVER_RES_MASKED);
    }
    else if(code == LV_EVENT_DRAW_MAIN_BEGIN) {
        lv_draw_mask_map_init(&m, &obj->coords, mask_map);
        mask_id = lv_draw_mask_add(&m, NULL);

    }
    else if(code == LV_EVENT_DRAW_MAIN_END) {
        lv_draw_mask_free_param(&m);
        lv_draw_mask_remove_id(mask_id);
    }
}

/**
 * Draw label with gradient color
 */
void lv_example_label_4(void)
{
    /* Create the mask of a text by drawing it to a canvas*/
    static lv_color_t mask_map[MASK_WIDTH * MASK_HEIGHT];

    /*Create a "8 bit alpha" canvas and clear it*/
    lv_obj_t * canvas = lv_canvas_create(lv_screen_active());
    lv_canvas_set_buffer(canvas, mask_map, MASK_WIDTH, MASK_HEIGHT, LV_COLOR_FORMAT_NATIVE);
    lv_canvas_fill_bg(canvas, lv_color_black(), LV_OPA_TRANSP);

    /*Draw a label to the canvas. The result "image" will be used as mask*/
    lv_draw_label_dsc_t label_dsc;
    lv_draw_label_dsc_init(&label_dsc);
    label_dsc.color = lv_color_white();
    label_dsc.align = LV_TEXT_ALIGN_CENTER;
    label_dsc.text = "Text with gradient";
    lv_canvas_draw_text(canvas, 5, 5, MASK_WIDTH, &label_dsc);

    /*The mask is reads the canvas is not required anymore*/
    lv_obj_delete(canvas);

    /*Convert the mask to A8*/
    uint32_t i;
    uint8_t * mask8 = (uint8_t *) mask_map;
    lv_color_t * mask_c = mask_map;
    for(i = 0; i < MASK_WIDTH * MASK_HEIGHT; i++) {
        mask8[i] = lv_color_brightness(mask_c[i]);
    }

    /* Create an object from where the text will be masked out.
     * Now it's a rectangle with a gradient but it could be an image too*/
    lv_obj_t * grad = lv_obj_create(lv_screen_active());
    lv_obj_set_size(grad, MASK_WIDTH, MASK_HEIGHT);
    lv_obj_center(grad);
    lv_obj_set_style_bg_color(grad, lv_color_hex(0xff0000), 0);
    lv_obj_set_style_bg_grad_color(grad, lv_color_hex(0x0000ff), 0);
    lv_obj_set_style_bg_grad_dir(grad, LV_GRAD_DIR_HOR, 0);
    lv_obj_add_event_cb(grad, add_mask_event_cb, LV_EVENT_ALL, mask_map);
}

#endif

示例4显示TODO,明显还没有完成,应该会随着后续升级完成,强行去掉0这个宏的话编译也会报错,这里看应该是想实现绘制画布来做label的一些功能,后续升级版本后再看看,可以订阅官方的邮箱来了解其更新情况。

1.5、label示例5(标签内容滚动动画效果)
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES

/**
 * 显示使用“LV_LABEL_LONG_SCROLL_CIRCULAR”自定义标签的圆形滚动动画长模式
 */
void lv_example_label_5(void)
{
    static lv_anim_t animation_template;
    static lv_style_t label_style;

    lv_anim_init(&animation_template);
    lv_anim_set_delay(&animation_template, 1000);           /*等待 1 秒开始第一个滚动*/
    lv_anim_set_repeat_delay(&animation_template,
                             3000);    /*标签滚动回初始位置后重复滚动 3 秒*/

    /*使用动画模板初始化标签样式*/
    lv_style_init(&label_style);
    lv_style_set_anim(&label_style, &animation_template);

    lv_obj_t * label1 = lv_label_create(lv_screen_active());
    lv_label_set_long_mode(label1, LV_LABEL_LONG_SCROLL_CIRCULAR);      /*循环滚动*/
    lv_obj_set_width(label1, 150);
    lv_label_set_text(label1, "It is a circularly scrolling text. ");
    lv_obj_align(label1, LV_ALIGN_CENTER, 0, 40);
    lv_obj_add_style(label1, &label_style, LV_STATE_DEFAULT);           /*将样式添加到标签*/
}

#endif

image.png
展示:

  • 延迟一秒后开始滚动,滚动三秒后回到初始状态
  • 实现label滚动效果的延迟处理

这种应该场景应该不是很多,所以基本上前三种示例满足大部分场景了。

2、button示例

button目前有三个示例。

2.1、button示例1(基础按钮和切换按钮)
#include "../../lv_examples.h"
#if LV_USE_BUTTON && LV_BUILD_EXAMPLES

static void event_handler(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);

    if(code == LV_EVENT_CLICKED) {
        LV_LOG_USER("Clicked");
    }
    else if(code == LV_EVENT_VALUE_CHANGED) {
        LV_LOG_USER("Toggled");
    }
}

void lv_example_button_1(void)
{
    lv_obj_t * label;

    lv_obj_t * btn1 = lv_button_create(lv_screen_active());
    lv_obj_add_event_cb(btn1, event_handler, LV_EVENT_ALL, NULL);
    lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -40);
    lv_obj_remove_flag(btn1, LV_OBJ_FLAG_PRESS_LOCK);

    label = lv_label_create(btn1);
    lv_label_set_text(label, "Button");
    lv_obj_center(label);

    lv_obj_t * btn2 = lv_button_create(lv_screen_active());
    lv_obj_add_event_cb(btn2, event_handler, LV_EVENT_ALL, NULL);
    lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 40);
    lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);
    lv_obj_set_height(btn2, LV_SIZE_CONTENT);

    label = lv_label_create(btn2);
    lv_label_set_text(label, "Toggle");
    lv_obj_center(label);

}
#endif

image.png
展示:

  • 如何创建button或者Toggle
  • button或者toggle上添加文本内容通过label来实现
  • toggle除了button的点击事件完,还有对应的切换事件,根据切换状态会更改对应颜色
  • 并且根据对应触发的事件可以在回调中做进一步处理
2.2、button示例2(按钮阴影和按钮点击后样式变化)
#include "../../lv_examples.h"
#if LV_USE_BUTTON && LV_BUILD_EXAMPLES

/**
 * 从头开始设计按钮
 */
void lv_example_button_2(void)
{
    /*初始化默认状态的样式*/
    static lv_style_t style;
    lv_style_init(&style);

    lv_style_set_radius(&style, 3);

    lv_style_set_bg_opa(&style, LV_OPA_100);
    lv_style_set_bg_color(&style, lv_palette_main(LV_PALETTE_BLUE));
    lv_style_set_bg_grad_color(&style, lv_palette_darken(LV_PALETTE_BLUE, 2));
    lv_style_set_bg_grad_dir(&style, LV_GRAD_DIR_VER);

    lv_style_set_border_opa(&style, LV_OPA_40);
    lv_style_set_border_width(&style, 2);
    lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_GREY));

    lv_style_set_shadow_width(&style, 8);
    lv_style_set_shadow_color(&style, lv_palette_main(LV_PALETTE_GREY));
    lv_style_set_shadow_offset_y(&style, 8);

    lv_style_set_outline_opa(&style, LV_OPA_COVER);
    lv_style_set_outline_color(&style, lv_palette_main(LV_PALETTE_BLUE));

    lv_style_set_text_color(&style, lv_color_white());
    lv_style_set_pad_all(&style, 10);

    /*初始化按下的样式*/
    static lv_style_t style_pr;
    lv_style_init(&style_pr);

    /*按下时添加大轮廓*/
    lv_style_set_outline_width(&style_pr, 30);
    lv_style_set_outline_opa(&style_pr, LV_OPA_TRANSP);

    lv_style_set_translate_y(&style_pr, 5);
    lv_style_set_shadow_offset_y(&style_pr, 3);
    lv_style_set_bg_color(&style_pr, lv_palette_darken(LV_PALETTE_BLUE, 2));
    lv_style_set_bg_grad_color(&style_pr, lv_palette_darken(LV_PALETTE_BLUE, 4));

    /*向轮廓添加过渡*/
    static lv_style_transition_dsc_t trans;
    static lv_style_prop_t props[] = {LV_STYLE_OUTLINE_WIDTH, LV_STYLE_OUTLINE_OPA, 0};
    lv_style_transition_dsc_init(&trans, props, lv_anim_path_linear, 300, 0, NULL);

    lv_style_set_transition(&style_pr, &trans);

    lv_obj_t * btn1 = lv_button_create(lv_screen_active());
    lv_obj_remove_style_all(btn1);                          /*删除来自主题的样式*/
    lv_obj_add_style(btn1, &style, 0);
    lv_obj_add_style(btn1, &style_pr, LV_STATE_PRESSED);
    lv_obj_set_size(btn1, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
    lv_obj_center(btn1);

    lv_obj_t * label = lv_label_create(btn1);
    lv_label_set_text(label, "Button");
    lv_obj_center(label);
}
#endif

image.png
展示:

  • button的初始化样式,比如阴影
  • 设置button点击后的样式,使其更加酷炫
2.3、button示例3(按钮样式过渡动画效果)
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_BUTTON

/**
 * 在按钮上创建样式过渡,单击时就像口香糖一样
 */
void lv_example_button_3(void)
{
    /*要转换的属性*/
    static lv_style_prop_t props[] = {
        LV_STYLE_TRANSFORM_WIDTH, LV_STYLE_TRANSFORM_HEIGHT, LV_STYLE_TEXT_LETTER_SPACE, 0
    };

    /*返回默认状态时的转换描述符。
     *添加一些延迟以确保即使按下时间很短,按下过渡也可见*/
    static lv_style_transition_dsc_t transition_dsc_def;
    lv_style_transition_dsc_init(&transition_dsc_def, props, lv_anim_path_overshoot, 250, 100, NULL);

    /*进入按下状态时的转换描述符。
     *无延迟,立即进入按下状态*/
    static lv_style_transition_dsc_t transition_dsc_pr;
    lv_style_transition_dsc_init(&transition_dsc_pr, props, lv_anim_path_ease_in_out, 250, 0, NULL);

    /*仅将新的转换添加到默认状态*/
    static lv_style_t style_def;
    lv_style_init(&style_def);
    lv_style_set_transition(&style_def, &transition_dsc_def);

    /*向按压状态添加过渡和一些转换。*/
    static lv_style_t style_pr;
    lv_style_init(&style_pr);
    lv_style_set_transform_width(&style_pr, 10);
    lv_style_set_transform_height(&style_pr, -10);
    lv_style_set_text_letter_space(&style_pr, 10);
    lv_style_set_transition(&style_pr, &transition_dsc_pr);

    lv_obj_t * btn1 = lv_button_create(lv_screen_active());
    lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -80);
    lv_obj_add_style(btn1, &style_pr, LV_STATE_PRESSED);
    lv_obj_add_style(btn1, &style_def, 0);

    lv_obj_t * label = lv_label_create(btn1);
    lv_label_set_text(label, "Gum");
}
#endif

image.png
展示:

  • 在按钮上创建样式过渡,单击时就像口香糖一样
  • 将多种样式融合起来,在点击过程中进行按钮样式过度,使其具备更加动态的显示效果,button点击起来更具备科技感和交互感

3、slider示例

3.1、slider示例1(基础滑块)
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES

static void slider_event_cb(lv_event_t * e);
static lv_obj_t * slider_label;

/**
 * 带有显示当前值的标签的默认滑块
 */
void lv_example_slider_1(void)
{
    /*在显示屏中央创建一个滑块*/
    lv_obj_t * slider = lv_slider_create(lv_screen_active());
    lv_obj_center(slider);
    lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);

    lv_obj_set_style_anim_duration(slider, 2000, 0);
    /*在滑块下方创建标签*/
    slider_label = lv_label_create(lv_screen_active());
    lv_label_set_text(slider_label, "0%");

    lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
}

static void slider_event_cb(lv_event_t * e)
{
    lv_obj_t * slider = lv_event_get_target(e);
    char buf[8];
    lv_snprintf(buf, sizeof(buf), "%d%%", (int)lv_slider_get_value(slider));
    lv_label_set_text(slider_label, buf);
    lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
}

#endif

image.png
展示:

  • 带有显示当前值的标签的默认滑块
3.2、slider示例2(设置滑块样式)
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES

/**
 * 展示如何设置滑块的样式
 */
void lv_example_slider_2(void)
{
    /*创建过渡*/
    static const lv_style_prop_t props[] = {LV_STYLE_BG_COLOR, 0};
    static lv_style_transition_dsc_t transition_dsc;
    lv_style_transition_dsc_init(&transition_dsc, props, lv_anim_path_linear, 300, 0, NULL);

    static lv_style_t style_main;
    static lv_style_t style_indicator;
    static lv_style_t style_knob;
    static lv_style_t style_pressed_color;
    lv_style_init(&style_main);
    lv_style_set_bg_opa(&style_main, LV_OPA_COVER);
    lv_style_set_bg_color(&style_main, lv_color_hex3(0xbbb));
    lv_style_set_radius(&style_main, LV_RADIUS_CIRCLE);
    lv_style_set_pad_ver(&style_main, -2); /*使指标变大*/

    lv_style_init(&style_indicator);
    lv_style_set_bg_opa(&style_indicator, LV_OPA_COVER);
    lv_style_set_bg_color(&style_indicator, lv_palette_main(LV_PALETTE_CYAN));
    lv_style_set_radius(&style_indicator, LV_RADIUS_CIRCLE);
    lv_style_set_transition(&style_indicator, &transition_dsc);

    lv_style_init(&style_knob);
    lv_style_set_bg_opa(&style_knob, LV_OPA_COVER);
    lv_style_set_bg_color(&style_knob, lv_palette_main(LV_PALETTE_CYAN));
    lv_style_set_border_color(&style_knob, lv_palette_darken(LV_PALETTE_CYAN, 3));
    lv_style_set_border_width(&style_knob, 2);
    lv_style_set_radius(&style_knob, LV_RADIUS_CIRCLE);
    lv_style_set_pad_all(&style_knob, 6); /*使旋钮变大*/
    lv_style_set_transition(&style_knob, &transition_dsc);

    lv_style_init(&style_pressed_color);
    lv_style_set_bg_color(&style_pressed_color, lv_palette_darken(LV_PALETTE_CYAN, 2));

    /*创建滑块并添加样式*/
    lv_obj_t * slider = lv_slider_create(lv_screen_active());
    lv_obj_remove_style_all(slider);        /*删除来自主题的样式*/

    lv_obj_add_style(slider, &style_main, LV_PART_MAIN);
    lv_obj_add_style(slider, &style_indicator, LV_PART_INDICATOR);
    lv_obj_add_style(slider, &style_pressed_color, LV_PART_INDICATOR | LV_STATE_PRESSED);
    lv_obj_add_style(slider, &style_knob, LV_PART_KNOB);
    lv_obj_add_style(slider, &style_pressed_color, LV_PART_KNOB | LV_STATE_PRESSED);

    lv_obj_center(slider);
}

#endif

image.png

  • 展示如何设置滑块的样式。
3.3、slider示例3(滑块值样式设置及显示)
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES

static void slider_event_cb(lv_event_t * e);

/**
 * 通过展开抽屉按下滑块时显示当前值
 *
 */
void lv_example_slider_3(void)
{
    /*在显示屏中央创建一个滑块*/
    lv_obj_t * slider;
    slider = lv_slider_create(lv_screen_active());
    lv_obj_center(slider);

    lv_slider_set_mode(slider, LV_SLIDER_MODE_RANGE);
    lv_slider_set_value(slider, 70, LV_ANIM_OFF);
    lv_slider_set_left_value(slider, 20, LV_ANIM_OFF);

    lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_ALL, NULL);
    lv_obj_refresh_ext_draw_size(slider);
}

static void slider_event_cb(lv_event_t * e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t * obj = lv_event_get_target(e);

    /*为该值提供一些额外的空间*/
    if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
        lv_event_set_ext_draw_size(e, 50);
    }
    else if(code == LV_EVENT_DRAW_MAIN_END) {
        if(!lv_obj_has_state(obj, LV_STATE_PRESSED)) return;

        lv_slider_t * slider = (lv_slider_t *) obj;
        const lv_area_t * indic_area = &slider->bar.indic_area;
        char buf[16];
        lv_snprintf(buf, sizeof(buf), "%d - %d", (int)lv_slider_get_left_value(obj), (int)lv_slider_get_value(obj));

        lv_point_t label_size;
        lv_text_get_size(&label_size, buf, LV_FONT_DEFAULT, 0, 0, LV_COORD_MAX, 0);
        lv_area_t label_area;
        label_area.x1 = 0;
        label_area.x2 = label_size.x - 1;
        label_area.y1 = 0;
        label_area.y2 = label_size.y - 1;

        lv_area_align(indic_area, &label_area, LV_ALIGN_OUT_TOP_MID, 0, -10);

        lv_draw_label_dsc_t label_draw_dsc;
        lv_draw_label_dsc_init(&label_draw_dsc);
        label_draw_dsc.color = lv_color_hex3(0x888);
        label_draw_dsc.text = buf;
        label_draw_dsc.text_local = true;
        lv_layer_t * layer = lv_event_get_layer(e);
        lv_draw_label(layer, &label_draw_dsc, &label_area);
    }
}

#endif

image.png

  • 展开抽屉按下滑块时显示当前值
3.4、slider示例4(滑块方向相反)
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES

static void slider_event_cb(lv_event_t * e);
static lv_obj_t * slider_label;

/**
 * 滑块方向相反
 */
void lv_example_slider_4(void)
{
    /*在显示屏中央创建一个滑块*/
    lv_obj_t * slider = lv_slider_create(lv_screen_active());
    lv_obj_center(slider);
    lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
    /*反转滑块的方向*/
    lv_slider_set_range(slider, 100, 0);
    /*在滑块下方创建标签*/
    slider_label = lv_label_create(lv_screen_active());
    lv_label_set_text(slider_label, "0%");

    lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
}

static void slider_event_cb(lv_event_t * e)
{
    lv_obj_t * slider = lv_event_get_target(e);
    char buf[8];
    lv_snprintf(buf, sizeof(buf), "%d%%", (int)lv_slider_get_value(slider));
    lv_label_set_text(slider_label, buf);
    lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
}

#endif

image.png

  • 滑块方向相反

三、最后

基本常用的几个基础控件就先总结到这里,接下来总结一下样式的相关使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/649139.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Textual for Mac:轻量级IRC客户端

在寻找一款高效、轻量级的IRC客户端时&#xff0c;Textual for Mac无疑是你的不二之选。它集成了众多现代技术&#xff0c;如本机IPv6、最新的IRCv3规范&#xff0c;以及客户端证书身份验证&#xff0c;让你的聊天体验更加顺畅和安全。 Textual for Mac v7.2.2免激活版下载 Tex…

代码随想录算法训练营第五十九天|503.下一个更大元素II、42. 接雨水

503. 下一个更大元素 II 思路&#xff1a; 这道题和739. 每日温度 (opens new window)也几乎如出一辙。 不过&#xff0c;本题要循环数组了。 本篇我侧重与说一说&#xff0c;如何处理循环数组。 相信不少同学看到这道题&#xff0c;就想那我直接把两个数组拼接在一起&…

MySQL导入SQL脚本---超详细介绍

1.新建xxx数据库&#xff0c;字符集选对。 2.在mysql安装目录下cmd进入小黑窗 3.执行mysql -uroot -p123456 --default-character-setutf8命令 4.use xxx; 5.source xxx.sql 执行完上面的命令等待结束就可以了 需要注意的是--default-character-setutf8&#xff0c;要不然可…

如何把学浪的视频保存到手机

你是不是还在为无法将学浪的视频保存到手机而烦恼&#xff1f;别担心&#xff0c;接下来我将为大家分享一个非常实用的方法&#xff0c;让你轻松实现这一目标&#xff01; 下载学浪的工具我已经打包好了&#xff0c;有需要的自己下载一下 学浪下载工具打包链接&#xff1a;百…

网络工程师备考2——vlan

vlan 1、什么是VLAN&#xff1f; VLAN&#xff08;Virtual LAN&#xff09;&#xff0c;翻译成中文是“虚拟局域网”。LAN可以是由少数几台家用计算机构成的网络&#xff0c;也可以是数以百计的计算机构成的企业网络。VLAN所指的LAN特指使用路由器分割的网络——也就是广播域…

DAOS: A Scale-Out High Performance Storage Stack for Storage Class Memory——论文泛读

Supercomputing Frontiers 2020 Paper 分布式元数据论文阅读笔记整理 问题 企业、政府和学术界出现的数据密集型应用程序将现有的I/O模型扩展到了极限。现代I/O工作负载的特点是元数据与未对齐和碎片化数据的结合比例越来越高。传统的存储堆栈为这些工作负载提供了较差的性能…

OrangePi AIPro:次世代嵌入式边缘AI计算与智能机器人应用开发平台

近年来,随着物联网(IoT)和人工智能(AI)技术的快速发展,嵌入式边缘计算板卡在智能设备中的应用越来越广泛。OrangePi AIpro作为一款轻量化高性能的嵌入式边缘人工智能计算SoC,在硬件配置、AI性能和使用便利性方面都有着突出的表现。本文将详细评测OrangePi AIpro的各个方…

项目文章 |NC揭示真菌中A-to-I mRNA编辑机制及其调控和演化

A-to-I mRNA编辑是一种重要的基因表达调控方式&#xff0c;它通过将mRNA中的腺苷(A)转变为肌苷(I)&#xff0c;从而可能改变蛋白质的编码信息。在动物中&#xff0c;这一过程由ADAR家族酶介导&#xff0c;然而在真菌中&#xff0c;由于缺乏ADARs的同源物&#xff0c;其背后的机…

python onnx 推理yolov10

python onnx 推理yolov10 import onnxruntime as ort import cv2 import numpy as np# Class names for the COCO dataset CLASSES = ["person", "bicycle", "car", "motorcycle", "airplane"

[猫头虎分享21天微信小程序基础入门教程]第19天:小程序的插件开发与使用

[猫头虎分享21天微信小程序基础入门教程]第19天&#xff1a;小程序的插件开发与使用 第19天&#xff1a;小程序的插件开发与使用 &#x1f527; 自我介绍 大家好&#xff0c;我是猫头虎&#xff0c;一名全栈软件工程师。今天我们继续微信小程序的学习&#xff0c;重点了解如…

StackExchange.Redis跑起来,为什么这么溜?

StackExchange.Redis 是一个高性能的 Redis 客户端库&#xff0c;主要用于 .NET 环境下与 Redis 服务器进行通信&#xff0c;大名鼎鼎的stackoverflow 网站就使用它。它使用异步编程模型&#xff0c;能够高效处理大量请求。支持 Redis 的绝大部分功能&#xff0c;包括发布/订阅…

SwiftUI 5.0(iOS 17)进一步定制 TipKit 外观让撸码如虎添翼

概览 在之前 SwiftUI 5.0&#xff08;iOS 17&#xff09;TipKit 让用户更懂你的 App 这篇博文里&#xff0c;我们已经初步介绍过了 TipKit 的基本知识。 现在&#xff0c;让我们来看看如何进一步利用 SwiftUI 对 TipKit 提供的细粒度外观定制技巧&#xff0c;让 Tip 更加“明眸…

灯塔工厂产业数字化平台解决方案(50页PPT)

方案介绍&#xff1a; 随着工业4.0和智能制造的快速发展&#xff0c;传统工厂正面临着转型升级的迫切需求。为了提升生产效率、优化资源配置、增强市场竞争力&#xff0c;我们推出了灯塔工厂产业数字化平台解决方案。该方案旨在通过先进的信息技术手段&#xff0c;将传统工厂转…

springboot发送短信验证码,结合redis 实现限制,验证码有效期2分钟,有效期内禁止再次发送,一天内发送超3次限制

springboot结合redis发送短信验证码,实现限制发送操作 前言(可忽略)实现思路正题效果图示例手机号不符合规则校验图成功发送验证码示例图redis中缓存随机数字验证码&#xff0c;2分钟后失效删除redis缓存图验证码有效期内 返回禁止重复发送图验证码24小时内发送达到3次&#xf…

Https自签名证书

openSSL下载 https://slproweb.com/products/Win32OpenSSL.html 1_整体流程 &#xff08;1&#xff09;https介绍 HTTPS 是 Hypertext Transfer Protocol Secure 的简称&#xff0c;是基于 SSL 加密方式的 HTTP 协议 &#xff08;2&#xff09;CA机构介绍 介绍&#xff1a…

2024年,游戏行业还值得进入吗?

来自知乎问题“2024年&#xff0c;游戏行业还值得进入吗&#xff1f;”的回答。 ——原问题描述&#xff1a;从超小厂执行策划做起&#xff0c;未来有前途吗&#xff1f; 展望2024年&#xff0c;国内外的游戏市场环境或将变得更加复杂&#xff0c;曾经那个水大鱼大的时代过去了…

考试宝典——软件过程与管理重点知识总结

概论 软件工程三要素 过程方法工具 软件过程的定义 软件过程是用于软件开发及维护的一系列活动、方法及实践。 常见软件过程分类&#xff08;五大类&#xff09; 客户-供应商过程&#xff1a;内部直接影响到客户、外部直接影响开发、向客户交付软件以及软件正确操作与使用的过…

路由器交换机直连方案(RM50+RTL8367N)

不经过网口和变压器&#xff0c;实现板级网口扩展。 通过网口&#xff0c;网线连接 板级芯片直接连接&#xff0c;验证OK 激光导航控制板通过路由器上网成功

二叉搜索树BST ——(C++)

本篇将会讲解有关二叉树的搜索原理&#xff0c;以及关于二叉搜索树的建立&#xff0c;以及二叉树搜索树的插入、删除和查找等基本操作。最后我们还会对二叉搜索树进行功能扩展&#xff0c;介绍有关搜索二叉树的 K 模型和 KV 模型。目录如下&#xff1a; 目录 1. 搜索二叉树 二叉…

PageHelper分页查询时,count()查询记录总数与实际返回的数据数量不一致

目录 场景简介代码判断异常情况排查原因解决 场景简介 1、使用PageHelper进行分页查询 2、最终构建PageInfo对象时&#xff0c;total与实际数据量不符 代码判断 异常情况 排查 通过对比count()查询的SQL与查询记录的SQL&#xff0c;发现是PageHelper分页查询时省去了order b…