LVGL学习笔记(三)
2026/8/9 8:55:38 网站建设 项目流程

LVGL学习笔记(三)

对象核心概念

前言

之前的两篇笔记中进行的示例都是在LVGL提供的官方示例中进行的,但对于实际工程而言,我们还是需要设计可视界面,而在LVGL中对象是最核心的概念,它是构建整个可视界面的基本单元。简单来说,可以将对象理解为游戏《我的世界》中的“积木块”,所有的界面元素都是由一个个对象组成的。

故这篇笔记开始,主要围绕LVGL中的对象相关的知识点展开,介绍对象的属性和样式等概念,最后举一个示例来演示如何创建一个对象。

  • 什么是对象?

    LVGL 图形库虽然是由 C 语言开发的,但其所采用的是一种面对对象编程思维。所谓面向对象,就是把现实中的事物都抽象为“对象”。每个对象是唯一的,且都可以拥有它的属性与行为。

    在LVGL中,无论是按钮、标签、文本框等基础控件,还是自主设计的复杂界面组件,本质上都是对象。它们都有各自不同的属性和行为,调用不同的属性就能实现界面的不同功能。关于不同控件的不同点,会在后续的学习笔记中提到。

    简单来说,把"对象"想象成一块积木块,一个按钮是一块积木,一行文字是一块积木,甚至整个屏幕也是一块积木。

  • 对象之间有什么关系?如何理解父对象和子对象?

    LVGL 采用父子结构管理对象。

    创建对象时候,首先要创建一个父对象,这个父对象一般有两种,分别是:

    • 使用对象A成为父对象。那边创建的对象B将会是对象A的子对象。
    • 使用屏幕作为父对象。在 LVGL中,屏幕是没有父对象的特殊对象,在默认的情况下,LVGL 初始化时,系统已经帮用户创建一个活动屏幕,不需要我们再次创建。

    每个对象必须有一个父对象(屏幕除外),而父对象可以包含多个子对象。子对象的位置相对于父对象,父对象移动时,子对象会随之移动。

    简单来说,你可以把一块积木放到另一块积木上面,放上去的那块就是"子",被放的那块就是"父"。

    假设我们的屏幕是一张“桌子”,那边父子积木的移动位置规律如下:

    • **子积木的位置是相对于父积木来算的。**假设将父积木放置在桌子的左上角,然后设置子积木的位置坐标为(10,10),那么子积木将会出现在父积木左上角往右往下各偏移10个像素的位置。

    • 父积木一动,所有子积木跟着动。假设从桌子上将左上角的积木搬到右下角,不用移动子积木,子积木会自动移动右下角的父积木左上角往右往下各偏移10个像素的位置。

    • 父积木被删掉,子积木也自动消失。我们把父积木从桌子上收到盒子里,子积木不用收,也会从桌子上消失。

    • 子积木超出父积木边界的部分会被"切掉"。如果子积木的体积大,父积木的体积小,由于父积木放不下这么大的子积木,超过父积木的子积木部分会被切除。

  • LVGL中的对象模型是什么?

    • 所有UI元素都是对象(Object)
    • 对象具有层级关系(父子关系)
    • 对象继承父对象的属性
    • 对象可以接收事件并作出响应
    • 对象有自己的样式和状态

    所谓的对象模型,承接上面的例子,就是所有界面元素都是"积木"(对象),积木之间有"父子嵌套"关系,所有积木共享一套通用的属性和操作方式,同时各自保留自己的特殊功能。只需要像搭积木一样,创建积木、设置样式、绑定事件、嵌套组合,就能搭出完整的界面。

    属性、事件这些概念会在后面的笔记中提及,这里不展开表述。使用LVGL对象模型有如下的优点:

    • 规则统一
    • 布局方便
    • 内存安全
  • C语言是面向过程的语言,在LVGL中如何使用面向对象思想创建对象?

    正如上面所讨论的,LVGL图形库是用C语言写的,使用到了“面向对象思想”,但C语言本身没有"类"和"继承"这些概念,故LVGL通过结构体的形式实现了“类”的功能(并非真的“类”),具体的实现逻辑如下图所示:

    由上图可知,在 LVGL 中,首先定义了 lv_obj_t 这个结构体,然后通过这个结构体去实例化一个基础对象(lv_obj),这个基础对象将作为父对象,去衍生更多的子对象(其他部件)。

    沿用上面的那个比喻,就是这些“积木”长得不同、功能不同,但它们有一些共同的特点:都有位置(放在哪)、大小(多大多小)、颜色、能不能被点击等等。然后通过这种“类”的方式去衍生其他部件,所衍生出来的部件将会继承父对象的一些基本属性,例如大小、位置、样式等等,因此我们可以通过一套统一的函数去管理不同部件的基本属性。

    下面介绍一下创建对象中使用到的函数,理解了这些函数的用法就可以创建我们这次的hello world示例了。

    lv_obj_t结构体的原型如下:

    typedefstruct_lv_obj_t{constlv_obj_class_t*class_p;// 指向对象类的指针,定义对象的行为和属性struct_lv_obj_t*parent;// 父对象指针,表示对象的层级关系_lv_obj_spec_attr_t*spec_attr;// 特殊属性指针,存储子控件、滚动条等信息_lv_obj_style_t*styles;// 样式指针,定义对象的外观#ifLV_USE_USER_DATAvoid*user_data;// 用户自定义数据(可选)#endiflv_area_tcoords;// 对象的坐标区域lv_obj_flag_tflags;// 对象的标志位,控制对象行为(如可见性、可点击性等)lv_state_tstate;// 对象的状态(如默认、按下、禁用等)uint16_tlayout_inv:1;// 布局无效标志uint16_tscr_layout_inv:1;// 屏幕布局无效标志uint16_tskip_trans:1;// 跳过过渡动画标志uint16_tstyle_cnt:6;// 样式数量uint16_th_layout:1;// 水平布局标志uint16_tw_layout:1;// 垂直布局标志}lv_obj_t;

    lv_label_create():创建标签对象

    LVGL 每个对象的创建函数都很类似,它们具有高度统一的风格,源码如下所示:

    lv_obj_t*lv_<widget>_create(lv_obj_t*parent);

    在上述源码中,widget 代表的是不同的部件,例如开关(switch)、按钮(btn)等。一般情况下,创建对象的函数只有一个形参,那就是*parent,它指向父类,该父类可以是当前的活动屏幕(lv_scr_act)或者是其他的部件。

    这里使用的是函数lv_label_create(),作用是创建一个用于显示文本信息的基本控件,在示例中用来显示文字hello world。

    lv_scr_act():获取当前活动的屏幕

    调用函数lv_scr_act(),可以获取当前活动的屏幕,其将返回指向活动屏幕的指针。源码如下所示:

    staticinlinelv_obj_t*lv_scr_act(void){returnlv_disp_get_scr_act(lv_disp_get_default());}

    可以看到函数lv_scr_act()实际调用的是函数lv_disp_get_scr_act(),其原型如下:

    lv_obj_t*lv_disp_get_scr_act(lv_disp_t*disp){if(!disp)disp=lv_disp_get_default();if(!disp){LV_LOG_WARN("no display registered to get its active screen");returnNULL;}returndisp->act_scr;}

    其中,形参disp是指向LVGL显示设备驱动的指针,返回值是指向当前活动屏幕对象的指针。

    lv_label_set_text():设置动态文本(字符串形式)

    其原型如下:

    voidlv_label_set_text(lv_obj_t*label,constchar*text);

    形参label:为标签对象,array是新的文本内容,函数无返回值。

    lv_obj_center()对象的对齐

    这个函数是用于将指定对象在其父对象或屏幕中居中显示。其函数原型如下:

    voidlv_obj_center(lv_obj_t*obj);

    参数obj指向需要居中的对象的指针,关于对象的大小和位置相关的内容,会在下一篇笔记中重点提到,这里只要会使用即可。

    了解完上述的函数,我们可以开始创建我们自己的界面了,这次的示例是屏蔽掉LVGL官方示例代码,创建一个有hello world的界面,具体代码如下:

    intmain(){lv_init();if(!lv_win32_init(GetModuleHandleW(NULL),SW_SHOW,800,480,LoadIconW(GetModuleHandleW(NULL),MAKEINTRESOURCE(IDI_LVGL)))){return-1;}lv_win32_add_all_input_devices_to_group(NULL);lv_mainstart();/* 测试的demo */// ----------------------------------// Demos from lv_examples// ----------------------------------// lv_demo_widgets(); // 屏蔽官方示例代码// lv_demo_benchmark();// ----------------------------------// Task handler loop// ----------------------------------while(!lv_win32_quit_signal){lv_task_handler();Sleep(1);}return0;}voidlv_mainstart(void){lv_obj_t*scr=lv_scr_act();//获取当前活动屏幕(默认只有一个屏幕)lv_obj_t*label=lv_label_create(scr);//创建一个标签(Label)对象,父对象是屏幕lv_label_set_text(label,"Hello World!");//设置标签的文本lv_obj_center(label);//将标签在屏幕上居中}

    测试结果如下:

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询