ucGUI学习小结

ucGUI学习小结简要总结了自己学习 ucGUI 并应用到工程中的整个过程 并提供整理好的相关资料下载

前言    

      做一个小项目时需要实现GUI及相关操作(响应按键)。用的SoC的优点是功耗低,但是受限于硬件能力,之前的SDK里并没有对GUI有很好的支持。后面对GUI的界面外观还有一定的要求,就在网上搜了一下开源GUI的相关资料。最终使用ucGUI实现了GUI操作,这里把相关的学习过程做一个简单小结,所有相关资料上传到了百度云盘(链接:http://pan.baidu.com/s/1qYvv84G 密码:1o4l)

      基本流程是选择开源GUI——移植ucGUI——实现GUI元素的显示——显示单页GUI界面——显示含有嵌套关系的GUI系统——优化显示流程。

1.选择开源GUI

      用的SoC不支持linux,也不是Cortex-M系列的,最后只找到了两个合适的开源GUI——zlggui和ucGUI。zlggui代码量非常小,实现的gui也十分简单,适合我这种新手入门。把代码简单过了一遍并移植了下,算是加深了LCD上显示汉字、图片的代码实现(移植过程我主要参考了http://www.openedv.com/posts/list/32830.htm内容,zlggui源码见网盘)。

2.移植ucGUI    

      接着就是自己最终使用的ucGUI了,我用了3.90版本,参考了STM32上移植ucGUI的流程实现了在自己项目中的移植(正点原子上有很多教学贴,我参考的是附件中《ZK_UCGUI移植解析.pdf》文件)。移植过程不算复杂,主要是提供(1)LCD初始化函数(2)LCD画点函数(3)LCD的一些参数配置(分辨率,RGB位数等)。之后使用ucGUI的函数成功显示出一串字符,移植大体完成。

3.实现GUI元素的显示    

      之后就是熟悉如何使用ucGUI的函数,我是一边看《ucGUI中文手册.pdf》一边用硬件来做实验验证。项目中没有要求实现动画,我就主要学习了文本显示、位图显示、按钮、窗口、抗锯齿的内容,后面也满足了开发要求。

      一个GUI操作界面,一般也就包含按钮、文本、背景图等元素,项目里主要就是实现显示图片和显示字符。显示图片就使用emwin提供的图片转换工具,将图片转换为c文件,调用ucGUI接口函数即可(工具见文件夹中emwin.zip)。试验后发现在使用工具转换位图时,选中压缩选项时生成的c文件大小要小很多,不过GUI显示图片花费的时间相对长一些(需要先解压缩得到像素点数据再显示)。

      显示字符方面包括汉字和非汉字,一种常用的方法是使用网友提供的小软件导入选择的字体生成对应c文件,之后调用ucGUI的显示字符函数显示即可,相关资料见《定制UCGUI使用的汉字库》文件夹。这种方法在显示字号较大的字体时锯齿明显,不太美观。之后在网上找到另一种方法,利用ucGUI的抗锯齿功能绘制字符,字符文件占用空间相对大些但是显示效果要好很多。我主要借鉴的是http://blog.sina.com.cn/s/blog_74bd70030102v8od.html,用到的工具见《FontCvtST》目录。

4.显示单页GUI界面

  显示元素实现后,就是尝试显示单页GUI界面,ucGUI教程里有提供过一个“对话框”控件,控件中可以按需求摆放一些元素(包括按钮、文本、图片等)并实现对这些元素操作(按钮按下、文本切换等)的响应。不过其响应函数相对复杂。自己偷懒采用的是使用窗口管理器方式,自己构造一个针对该界面的响应函数,伪代码如下:

static void _cbWindow1(WM_MESSAGE *pMSG)

{

  /*窗口1的响应函数*/

}

static void _cbWindow2(WM_MESSAGE *pMSG)

{

  /*窗口2的响应函数*/

}

void gui_demo(MENU_KEY *key)

{  

  创建各个窗口及其界面元素(按钮、文本等),只执行一次;

  switch(*key)

  {

     /*让窗口响应按键值实现文本切换等效果*/

    WM_Invalidate(&window1);

    /*根据按键值更新界面指针等*/

  }

}

    之后在循环任务中循环调用该函数即可实现该界面对于不同按键的响应。

5.显示含有嵌套关系的GUI系统

      GUI操作界面一般不止一页,而是多页且多级的。为了实现不同界面的切换,自己使用链表将不同的GUI界面串联起来;同时为了统一循环任务中对界面GUI响应函数的调用形式,使用一个全局指针指向当前工作的界面。给出部分代码如下:

(1)定义一个结构体表示一个GUI页面

struct func_node

{

  void (*p_func)(MENU_KEY *key);//上面描述的该界面的响应函数,项目中界面响应按键值来更新

  void (*p_clear)(void);//销毁该界面的函数

  struct func_node *pre_node;//同一级的该界面的上一个界面

  struct func_node *next_node;//同一级的该界面的下一个界面

  struct func_node last_level;//上一级的界面

  struct func_node next_level;//下一级界面

}

(2)将各个界面串联起来

      假如有界面A、B、C,B和C为二级界面,且都是A的下一级界面。代码实现思想如下:

struct func_node node_A, node_B, node_C;

struct func_node *pnode, *pnode_level_1, *pnode_level_2;

      其中pnode始终指向要显示的界面;pnode_level_1始终指向要显示的一级界面;pnode_level_2始终指向要显示的二级界面。之后初始化各个func_node变量,并利用链表串联起来

pnode_level_1 = &node_A;

pnode_level_2 = &node_B;

pnode_level_1->next_level = &pnode_level_2;

node_B.next_node = &node_C;

node_C.pre_node = &node_B;

p_node = pnode_level_1;

(3)界面的响应函数中更新指向界面的指针

      函数void (*p_func)(MENU_KEY *key)就是上一小节中定义的界面响应函数,函数中需要包含根据按键值实时修改p_node、p_node_level_1和p_node_level_2部分。目的在于使它们分别始终指向要显示的界面、要显示的一级界面和要显示的二级界面。当需要更换界面时,如下更新p_node

void (*p_func)(MENU_KEY *key)

{

  switch(*key)

  {

    /*更新指向界面的指针p_node、p_node_level_1和p_node_level_2*/

    如果需要切换到下一级菜单

      p_node = (struct func_node *)*(pnode->next_level);

    如果切换到上一级菜单

      p_node = (struct func_node *)*(pnode->last_level);

    如果切换同一级的下一页菜单

      p_node = p_node->next_node;

    如果切换同一级的上一页菜单

      p_node  = p_node->pre_node;

  }

}

(4)界面响应函数的调用

      在循环任务中如下执行

while(1)

{

  获得按键值key;

  p_node->p_func(key);

}

    这样处理,每一个界面对应一个单独的界面响应函数,将复杂的响应处理封装在p_func()中;同时在循环任务中统一了调用界面响应函数的接口。 

6.优化显示流程

      后面感觉GUI刷新速率不够快,在网上搜到一些有关优化显示流程的资料。优化主要包括以下几个方面:

(1)优化ucGUI的画点函数,该函数是被调用的最频率的函数,因此优化效果十分显著。

(2)利用lcd控制芯片的特性优化ucGUI的划线函数

(3)利用ucGUI的窗口缓存,分配较大的内存用于缓存窗口绘制

      具体我参考了文件中《ucgui液晶显示深度优化篇.pdf》文档,也上传到了云盘中。

7.其他

http://www.eepw.com.cn/article/272288.htm中介绍了ucGUI绘制GIF动画

http://bbs.armfly.com/read.php?tid=377中有很多关于ucGUI的资料,十分给力

      整体来说比较偷懒地使用了ucGUI提供的功能,也满足了项目需求。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/215858.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午1:00
下一篇 2026年3月18日 下午1:00


相关推荐

  • webpack+vue项目实战(四,前端与后端的数据交互和前端展示数据)

    webpack+vue项目实战(四,前端与后端的数据交互和前端展示数据)

    2021年10月11日
    63
  • vscode搭建react框架(vscode补全js方法)

    文章目录一、安装node二、配置淘宝镜像三、配置vscode(win10)四、全局安装脚手架五、创建项目一、安装node请在官网下载安装:https://nodejs.org/zh-cn/vscode中点击(ctrl+`)调出终端输入指令node-v,能显示版本号,说明node已经装好了输入指令npm-v,能显示版本号,说明npm可以使用了点击链接查看图文教程https://blog.csdn.net/qq_45677671/article/detail

    2022年4月12日
    247
  • 04边界值分析法

    04边界值分析法04 边界值分析法 1 边界值分析法的介绍和概念 边界值分析是一种常用的黑盒测试方法 是对等价类划分方法的补充 所谓边界值 是指相对于输入等价类和输出等价类而言 稍高于其最高值或稍低于最低值的一些特定情况 边界值分析的步骤包括确定边界 选择测试用例两个步骤 根据大量的测试统计数据 很多错误是发生在输入或输出范围的边界上 而不是发生在输入 输出范围的中间区域 因此针对各种边界情况

    2026年3月18日
    2
  • 渗透测试文章_黑客秘笈-渗透测试实用指南

    渗透测试文章_黑客秘笈-渗透测试实用指南【拿shell】1.直接上传aspasajspcerphpaspxhtrcdx格式的木马,不行就利用IIS6.0解析漏洞”:1.asp;1.jpg/1.asp;.jpg/1.asp;jpg/1.asp;.xls2.上传图片木马遇到拦截系统,连图片木马都上传不了,记事本打开图片木马在代码最前面加上gif89a,一般就能逃过拦截系统了。3.上传图片木马把地址复制到…

    2026年2月9日
    6
  • StringUtils里面的 isEmpty方法和isBlank方法的区别[通俗易懂]

    StringUtils里面的 isEmpty方法和isBlank方法的区别[通俗易懂]写在前面:我是扬帆向海,这个昵称来源于我的名字以及女朋友的名字。我热爱技术、热爱开源、热爱编程。技术是开源的、知识是共享的。这博客是对自己学习的一点点总结及记录,如果您对Java、算法感兴趣,可以关注我的动态,我们一起学习。 用知识改变命运,让我们的家人过上更好的生活。文章目录1、isEmpty()方法2、isBlank()方法3、总结1、isEmpty()方法源码:…

    2022年6月11日
    40
  • python waitpid_waitpid使用的一点问题

    python waitpid_waitpid使用的一点问题使用 waipid 的时候遇到了一个奇怪的问题 将情况简化后描述一下 示例代码如下所示 主进程会处理 SIGCHLD 信号 处理过程是等待子进程结束 如果子进程正常退出 打印捕获到了 SIGCHLD 信号 否则打印错误码 让主进程后面 sleep3s 是为了防止主进程先于子进程退出 从而没办法响应子进程的退出信号 测试正常 fork 的情况注释掉 capture2 和 testsystem 部分 使用 capture1 和 t

    2026年3月16日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号