阅读并理解lv_demo_widgets()函数

现在我就是一个小白,我们用左键点进去这个函数lv_demo_widgets(),在LVGL.Simulator.cpp文件107行中。当前任务就是理解这部分代码,它在干了些什么事情,为什么这样设置,能不能不这样设置?我们把代码分为3部分看:

  1. 设置屏幕大小
  2. 设置字体和样式,样式包括文本颜色,边框等等。
  3. 创建了lv_tabview,增加了3个tab,Profile、Analytics、Shop。

设置屏幕大小

把代码放上来:

if(LV_HOR_RES <= 320) disp_size = DISP_SMALL;else if(LV_HOR_RES < 720) disp_size = DISP_MEDIUM;else disp_size = DISP_LARGE;

理解起来还比较容易,判断当前屏幕横向大小,然后定义屏幕的size为小、中、大。
接下来我们理解 LV_HOR_RES 代表什么意思?继续左键点进去看。在lv_disp.h这个头文件中看到了定义:

#ifndef LV_HOR_RES
/*** The horizontal resolution of the currently active display.*/
#define LV_HOR_RES lv_disp_get_hor_res(lv_disp_get_default())
#endif

实现是在lv_hal_disp.c文件中

/*** Get the horizontal resolution of a display* @param disp pointer to a display (NULL to use the default display)* @return the horizontal resolution of the display*/
lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp)
{if(disp == NULL) disp = lv_disp_get_default();if(disp == NULL) {return 0;}else {switch(disp->driver->rotated) {case LV_DISP_ROT_90:case LV_DISP_ROT_270:return disp->driver->ver_res;default:return disp->driver->hor_res;}}
}

用在线的翻译框翻译一下,

这时,可以知道,LV_HOR_RES 是可以直接获取默认屏幕的水平分辨率的,就是横向尺寸。我提个问题,分辨率是像素吗?百度百科中说,描述分辨率单位有很多,重要两个dpi(点每英寸),ppi(像素每英寸)。ppi是主要用在显示领域,dpi则是在打印领域。

  • dpi:点每英寸是描述在水平的和垂直的方向上,每英寸距离的图像包含多少个打印点
  • ppi:它是描述在水平的和垂直的方向上,每英寸距离的图像包含的像素(pixel)数目
    在这里应该是可以理解问像素的。

DISP_SALL 这3个呢?这里只是知道它们是一个disp_size_t的枚举,看不出来是啥?先跳过。

/***********************      TYPEDEFS**********************/
typedef enum {DISP_SMALL,DISP_MEDIUM,DISP_LARGE,
}disp_size_t;

设置字体和样式

同样地,先上代码

// 文件内的静态定义
static const lv_font_t * font_large;
static const lv_font_t * font_normal;// lv_demo_widgets 函数内容font_large = LV_FONT_DEFAULT;font_normal = LV_FONT_DEFAULT;lv_coord_t tab_h;if(disp_size == DISP_LARGE) {tab_h = 70;
#if LV_FONT_MONTSERRAT_24font_large     =  &lv_font_montserrat_24;
#elseLV_LOG_WARN("LV_FONT_MONTSERRAT_24 is not enabled for the widgets demo. Using LV_FONT_DEFAULT instead.");
#endif
#if LV_FONT_MONTSERRAT_16font_normal    =  &lv_font_montserrat_16;
#elseLV_LOG_WARN("LV_FONT_MONTSERRAT_16 is not enabled for the widgets demo. Using LV_FONT_DEFAULT instead.");
#endif} else if(disp_size == DISP_MEDIUM) {tab_h = 45;
#if LV_FONT_MONTSERRAT_20font_large     =  &lv_font_montserrat_20;
#elseLV_LOG_WARN("LV_FONT_MONTSERRAT_20 is not enabled for the widgets demo. Using LV_FONT_DEFAULT instead.");
#endif
#if LV_FONT_MONTSERRAT_14font_normal    =  &lv_font_montserrat_14;
#elseLV_LOG_WARN("LV_FONT_MONTSERRAT_14 is not enabled for the widgets demo. Using LV_FONT_DEFAULT instead.");
#endif} else { /* disp_size == DISP_SMALL */tab_h = 45;
#if LV_FONT_MONTSERRAT_18font_large     =  &lv_font_montserrat_18;
#elseLV_LOG_WARN("LV_FONT_MONTSERRAT_18 is not enabled for the widgets demo. Using LV_FONT_DEFAULT instead.");
#endif
#if LV_FONT_MONTSERRAT_12font_normal    =  &lv_font_montserrat_12;
#elseLV_LOG_WARN("LV_FONT_MONTSERRAT_12 is not enabled for the widgets demo. Using LV_FONT_DEFAULT instead.");
#endif}#if LV_USE_THEME_DEFAULTlv_theme_default_init(NULL, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), LV_THEME_DEFAULT_DARK, font_normal);
#endiflv_style_init(&style_text_muted);lv_style_set_text_opa(&style_text_muted, LV_OPA_50);lv_style_init(&style_title);lv_style_set_text_font(&style_title, font_large);lv_style_init(&style_icon);lv_style_set_text_color(&style_icon, lv_theme_get_color_primary(NULL));lv_style_set_text_font(&style_icon, font_large);lv_style_init(&style_bullet);lv_style_set_border_width(&style_bullet, 0);lv_style_set_radius(&style_bullet, LV_RADIUS_CIRCLE);

从字面上理解,定义了两个lv_font_t * 的指针,都指向了LV_FONT_DEFAULT这个变量。根据屏幕水平分辨率去判断使用的字号,比如,大尺寸的时候,大字体是使用24号,正常的使用16号的,字体用的MONTSERRAT这款字体。分别设置文本、图标、按钮。(style_bullet,我这里理解问按钮样式了)。
中午接着补上内容,先搬砖。

lv_font_t

先看一下这个是什么东西?在lv_font.h里面有定义:

typedef struct _lv_font_t {/** Get a glyph's descriptor from a font*/bool (*get_glyph_dsc)(const struct _lv_font_t *, lv_font_glyph_dsc_t *, uint32_t letter, uint32_t letter_next);/** Get a glyph's bitmap from a font*/const uint8_t * (*get_glyph_bitmap)(const struct _lv_font_t *, uint32_t);/*Pointer to the font in a font pack (must have the same line height)*/lv_coord_t line_height;         /**< The real line height where any text fits*/lv_coord_t base_line;           /**< Base line measured from the top of the line_height*/uint8_t subpx  : 2;             /**< An element of `lv_font_subpx_t`*/int8_t underline_position;      /**< Distance between the top of the underline and base line (< 0 means below the base line)*/int8_t underline_thickness;     /**< Thickness of the underline*/const void * dsc;               /**< Store implementation specific or run_time data or caching here*/const struct _lv_font_t * fallback;   /**< Fallback font for missing glyph. Resolved recursively */
#if LV_USE_USER_DATAvoid * user_data;               /**< Custom user data for font.*/
#endif
} lv_font_t;

如果需要理解这个是什么意思?需要补一些关于字体的知识,后面要调字体也会用到freetype2,所以可以找这方面的知识,在csdn站内也有很多这些知识,可以搜来学习。还推荐一个苹果的字体手册fonts.
这里面说明一个truetype字体文件内容,其实可以这么理解,就是有一个字体数据库,库里面有各种字体的位图,他们放在不同的表里面。怎么查到这些字体内,一般根据unicode码去索引。再来看位图1 里面有什么信息:这个定义了字体的baseline,字体宽度,字体高度等信息。
图1:

如果使用freetype的话,这里用了一张绿野耕夫博客的图,看到一个字体的信息有这么多信息
图2:

回到lv_font_t这个结构体重看,应该能看懂一些了,重要的如:

  • get_glyph_dsc : 或者字体描述的,如是什么字体等信息
  • const uint8_t * : 位图信息
  • line_height : 实际行高

其实用我们古代的活字印刷术更好理解,先把写好的字体放在文件中,你要用的时候就先找到里面的文字,最后根据设置的比例印到屏幕上。这样屏幕就能看到文字了。

查看lv_font_montserrat_24这个结构体

从上面代码看,当disp_size = DISP_LARGE 时, font_large = &lv_font_montserrat_24。我们点进去看这个结构体。
代码在lv_font_montserrat_24.c文件中,如下:

if LV_VERSION_CHECK(8, 0, 0)
const lv_font_t lv_font_montserrat_24 = {
#else
lv_font_t lv_font_montserrat_24 = {
#endif.get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt,    /*Function pointer to get glyph's data*/.get_glyph_bitmap = lv_font_get_bitmap_fmt_txt,    /*Function pointer to get glyph's bitmap*/.line_height = 27,          /*The maximum line height required by the font*/.base_line = 5,             /*Baseline measured from the bottom of the line*/
#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0).subpx = LV_FONT_SUBPX_NONE,
#endif
#if LV_VERSION_CHECK(7, 4, 0).underline_position = -2,.underline_thickness = 1,
#endif.dsc = &font_dsc           /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */
};

这里只是简单地定义了一个结构体,接着看到两个重要的函数:

  • lv_font_get_glyph_dsc_fmt_txt
  • lv_font_get_bitmap_fmt_txt

好奇,继续看一下这两个函数。

lv_font_get_glyph_dsc_fmt_txt

这个函数,前面理解是获取到字体的字体描述,这里可以印证一下。先贴一段代码:

/*** Used as `get_glyph_dsc` callback in LittelvGL's native font format if the font is uncompressed.* @param font_p pointer to font* @param dsc_out store the result descriptor here* @param letter an UNICODE letter code* @return true: descriptor is successfully loaded into `dsc_out`.*         false: the letter was not found, no data is loaded to `dsc_out`*/
bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter,uint32_t unicode_letter_next)
{bool is_tab = false;if(unicode_letter == '\t') {unicode_letter = ' ';is_tab = true;}lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc;uint32_t gid = get_glyph_dsc_id(font, unicode_letter);if(!gid) return false;int8_t kvalue = 0;if(fdsc->kern_dsc) {uint32_t gid_next = get_glyph_dsc_id(font, unicode_letter_next);if(gid_next) {kvalue = get_kern_value(font, gid, gid_next);}}/*Put together a glyph dsc*/const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];int32_t kv = ((int32_t)((int32_t)kvalue * fdsc->kern_scale) >> 4);uint32_t adv_w = gdsc->adv_w;if(is_tab) adv_w *= 2;adv_w += kv;adv_w  = (adv_w + (1 << 3)) >> 4;dsc_out->adv_w = adv_w;dsc_out->box_h = gdsc->box_h;dsc_out->box_w = gdsc->box_w;dsc_out->ofs_x = gdsc->ofs_x;dsc_out->ofs_y = gdsc->ofs_y;dsc_out->bpp   = (uint8_t)fdsc->bpp;if(is_tab) dsc_out->box_w = dsc_out->box_w * 2;return true;
}

从这里可以看到,并没有获取整体字体信息,我原本以为是能够获取到如微软雅黑这种整体的字体信息。从返回值看,反而是获取到某个字体的盒子信息,如:

  • adv_w :字体间距
  • box_h : 盒子高度

等等,可以配合上面图2的值看。这段代码,用当前的unicode字符和下一个unicode字符去获取当前的字体盒子信息。其中get_glyph_dsc_id() 函数是根据unicode字符获取位图id, get_kern_value()根据2个gid去获取kern 信息,即字符间距,最终的字符间距是要和缩放比例计算的。
只懂CRUD的我,这个函数可以通过字符索引到字符的id,并且通过id能拿到字符的高度间距等信息。接下来看另一个函数:

lv_font_get_bitmap_fmt_txt

看注释Function pointer to get glyph’s bitmap,是能够获取到字符的位图的函数的。点进去看代码:

const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t unicode_letter)
{if(unicode_letter == '\t') unicode_letter = ' ';lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc;uint32_t gid = get_glyph_dsc_id(font, unicode_letter);if(!gid) return NULL;const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid];if(fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN) {return &fdsc->glyph_bitmap[gdsc->bitmap_index];}..... //省略else部分
}

为什么省略呢,不占边幅,else是说明怎么从压缩字体中获取位图,可自行了解。这里只看if true部分,先获取到字体的描述函数,根据unicode获取字符的id,根据id查找到具体的字符位图信息,这里面包括了位图信息,盒子信息,就是lv_font_get_glyph_dsc_fmt_txt函数运行的结果,条件是先判断字符位图的格式 == LV_FONT_FMT_TXT_PLAIN。最后返回位图字节数组。

其实,这时候有个问题想问一下,这两个函数在什么地方调的呢?按照理解,应该是在渲染文字的时候会调用的。

字体这部分的总结

我们提供了一个结构体,这个结构体定义了2个重要的函数,这2个函数能够帮助我们根据字符去找到字符的描述信息,以及最终需要渲染的位图信息。这些位图信息也是我们提供的,这里看一下最终渲染的位图是啥样的?
在lv_font_montserrat_24.c文件拉到最开始的地方,这个uint8_t的字符数组
const uint8_t glyph_bitmap[],就是我们提供的位图信息:

static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {/* U+0020 " " *//* U+0021 "!" */0x1f, 0xf8, 0x1f, 0xf8, 0xf, 0xf7, 0xf, 0xf7,0xf, 0xf6, 0xe, 0xf5, 0xe, 0xf5, 0xd, 0xf4,0xd, 0xf3, 0xc, 0xf3, 0xb, 0xf2, 0x7, 0xa1,0x0, 0x0, 0x0, 0x0, 0x1d, 0xf6, 0x4f, 0xfb,0xc, 0xe5,}

这些信息要怎么获取呢?lvgl提供了工具font工具可以从ttf,woff 等字体文件中提取,当然也可以从freetype提供的库直接从ttf文件中提取。这两者的区别是啥?提供静态字符的方式,每定义一个字号都需要一个文件,lv_font_montserrat_24、lv_font_montserrat_16、lv_font_montserrat_14,如果你的项目需要更多变化的字号,则需要更多的文件。所以这需要看你项目的取舍了,因为加载freetype库也需要占用内存的。这里想吐槽一个事,如果弄中文的是不现实的,用例子的方式是不现实的,因为全中文有2万7千个字符左右,常用的需要7000个才能覆盖,除非你能确定字符的使用边界。
接下来我们看样式部分,分在另外一篇写了,这里太长了,继续学习吧。

阅读并理解lv_demo_widgets()函数相关推荐

  1. 第十四周 程序阅读,理解虚函数与纯虚函数

    /* * 程序的版权和版本声明部分 * Copyright (c)2012, 烟台大学计算机学院学生 * All rightsreserved. * 作者: 李洋 * 完成日期: 2013年 5 月 ...

  2. 前端 · 深入理解 transform 函数的计算原理 ②

    前排提示:本篇为该系列第二篇,内容相对于第一篇来说比较简单,各位可当休闲读物来看. <前端 · 深入理解 transform 函数的计算原理 ①> 接上回书讲到,我们知道了 transfo ...

  3. javascript之异步操作理解---回调函数,async,await以及promise对象

    javascript之异步操作理解---回调函数,async,await以及promise对象 概述 概述 写在前面:虽然平时做项目,但是发现自己写的代码还是很烂.最近接触了一个对性能要求比较高的项目 ...

  4. 深入理解javascript函数系列第二篇——函数参数

    前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数.本文是深入理解javascript函数 ...

  5. R语言使用gt包和gtExtras包优雅地、漂亮地显示表格数据:使用gt包可视化表格数据,使其易于阅读和理解、使用gtExtras包添加一个图,显示表中某一列中的数字

    R语言使用gt包和gtExtras包优雅地.漂亮地显示表格数据:使用gt包可视化表格数据,使其易于阅读和理解.使用gtExtras包添加一个图,显示表中某一列中的数字 目录

  6. R语言使用gt包和gtExtras包优雅地、漂亮地显示表格数据:使用gt包可视化表格数据,使其易于阅读和理解、使用gtExtras包添加一个图,显示表中某一列中的数字、并为类型数据添加图像符号标签

    R语言使用gt包和gtExtras包优雅地.漂亮地显示表格数据:使用gt包可视化表格数据,使其易于阅读和理解.使用gtExtras包添加一个图,显示表中某一列中的数字.并为类型数据添加图像符号标签 目 ...

  7. C++深入理解虚函数

    c++深入理解虚函数 虚函数的使用方法: (1)在基类用virtual声明成员函数为虚函数.这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便被调用. 在类外定义虚函数时,不必在定义vir ...

  8. 【Python】深入理解Python函数的9个黄金法则

    编程离不开函数.Python的函数除了具备传统意义上的函数特征外,又被赋予了其他一些特性,让它更灵活.更强大.这篇文章结合之前我推荐的一本Python宝书,又添加一些我的实践和理解,总结了深入理解Py ...

  9. python函数可以作为容器对象吗_正确理解Python函数是第一类对象

    正确理解 Python函数,能够帮助我们更好地理解 Python 装饰器.匿名函数(lambda).函数式编程等高阶技术. 函数(Function)作为程序语言中不可或缺的一部分,太稀松平常了.但函数 ...

最新文章

  1. iOS 图片渲染及优化
  2. Linux平台Oracle多个实例启动说明
  3. asp.net中异步调用WebService(异步页)[转]
  4. 安卓3d游戏开发引擎_鲁大师安卓3D引擎更新,跑分测试精准度再升级
  5. r(AB)=r(B)则方程组ABX=0与Bx=0有完全相同的解
  6. 使用git管理工具sourcetree拉取代码
  7. 微带天线:介质的材料分析
  8. Redis穿透、击穿、雪崩解决方案
  9. ACM算法模板小汇总
  10. Elastic 7.13.0 版重磅发布:在 Elastic 上搜索和存储更多数据
  11. 线性代数 --- 用条件数(condition number)来判断矩阵是否可逆
  12. 一文看懂企业数据资产目录
  13. 自定义Android键盘
  14. 监控远程log4.net日志
  15. 【时空序列预测第十五篇】HPRNN: A HIERARCHICAL SEQUENCE PREDICTION MODEL FOR LONG-TERM WEATHER RADAR ECHO EXTRAPO
  16. AlexNet论文翻译与解读
  17. 国家网络安全宣传周开幕 志翔科技护航核心数据与业务安全
  18. PS安装插件提示无法加载扩展未正确签署解决方式(适用于mac/win)
  19. 知道答案在哪里比知道答案更重要
  20. 读书笔记—《20岁的生活方式,决定30岁的打开方式》小令君

热门文章

  1. KindEditor编辑器结合EasyUi
  2. 【HTML5】html5中列表、表格、表单控件、浮动框架及结构化标签知识详解大全
  3. 如何更改计算机上面的图表形式,excel表格数据转换图形-怎么把EXCEL中的一组数字转换成图表形式...
  4. 无土栽培远程监空技术方案
  5. js获取指定字符后面的字符
  6. 关于Arduino、树莓派和 Pixhawk微处理器对比分析
  7. 此mac已与apple id关联(如何绕过macOS恢复模式的激活锁)
  8. 期刊论文发表的字数不够怎么办
  9. 基于Visual C++2010 与office2010开发办公自动化(2)-自动生成excel与word并打开
  10. html 文字输出语音,网页上通过JS实现文本的语音朗读