当前位置: 首页 > article >正文

【嵌入式】总结——Qt开发(四)

        与前面一致,主要目的是为了快速上手体验,并没有深入研究。本篇是对初学Qt的一次总结,并非终点。

        本阶段的目的是搭建桌面-应用基本框架,并开发一个“App”。正点原子给的综合例程源码使用的是QML,本篇与其一致。


 

        人机对战时要注意,AI可以从零生成你要的效果,你让它在此基础上添加或者优化是没有任何问题的,它可以一直给你堆叠特效,但让它修改、修复或调整是很容易出现问题的。讲一个我遇到的,让它生成应用图标的样式,它做得很好,让它在此基础上增加一些点击效果,也没有任何问题。但是让它调整代码,它常常会把函数或变量的定义域搞错,把错误提示信息给它也很难解决,只能凭借人的肉眼观察。

        初期,AI给你框架,让你根据这个框架来生成整个应用,但由于对话长度有限,所以不可能根据一个对话完成所有应用的设计。但初期的目的是让人跟AI学习,来掌握项目架构怎么设计,怎么模块化开发。当熟悉之后,把这个项目分解成若干模块,每个模块又可以让AI分成若干小模块 ,由于单个对话的限制,AI不可能把每个小模块是干什么的给理清,但能分成若干小模块也够了。接着可以再开个对话让AI来设计小模块

一、学习

1,基础开发框架

        新学一门编程语言时,我一般会先查看已有的源码,观察它的语法,看看哪些部分可以一眼看懂是干什么的,比如变量的定义和函数的定义使用,在各个编程语言里基本大同小异。然后再询问一些不太能理解的语法,让AI举一些例子,自己尝试对已有源码改一下,观察能否达到预期效果。重头学一遍那是不可能的,仿照例子重新写一遍那也是不可能的。

        改的过程中可能会遇到各种各样的问题,也会积累一些经验,见得多了不自觉就会写了

  • 如果添加了新的qml想要使用它,那么必须在qrc里添加该文件,这样在别的qml文件里使用import就可以导入对应的目录了。
  • 最容易出现的问题就是忘记添加qml到qrc里了,如果你发现某个自定义组件找不到,那么就看看它是否在qrc里。
  • 信号与槽:子组件的信号处理过程,既可以调用本地函数也可以触发本地信号(信号传递)
  • …………

        在对语法有一些初步认识后(至少能分清哪些代码块大致是干什么的,不需要很清楚),就准备尝试在已有代码的基础上重新构建(原项目不删除,用于参考),即新建一个空的桌面文件(Desktop.qml),把桌面的程序接口接到这个新建的桌面文件,不做什么大的改动。

        此时,我会问问AI项目怎么组织,毕竟对这门语言啥都不懂,为了便于后续扩展,项目的组织架构是尤为重要的,最好在开头就想好。

        然后根据自己的理解询问一些项目的细节,不懂就问

        不断讨论项目细节,比如在原先架构上,如果添加更多应用怎么办,尽可能考虑后续扩展,争取获得一个合适的项目结构

2,测试框架

        接着AI会给出项目组织架构和具体的代码,但这个代码一般都很后期,虽然内容不多,但往往包含了各个门类、各种细节,会调用各种本地的资源(实际上咱才开始,自然什么都没有)。此时,我一般会给AI一个我认为合适的项目组织架构,然后让它生成个简单的测试框架,最好没有任何依赖,仅仅靠原生组件来完成设计

         依照这个简单测试应用,一步一步搭建,最后搭建一个基础可用的桌面,基于此不断优化,比如下图。说着挺简单的,但实际上会出各种各样的问题,有时候还可能重新设计方案。比如管理应用时,一开始AI给的是StackView(当时还不知道Loader,以为这个与安卓开发的那个栈是一样的),但后续想要做一个返回主菜单键和退出应用键时,用起来就很麻烦。不得以向AI抱怨,得知StackView适合做单应用页面的管理,多应用导航控制用Loader更好,在项目开始时AI竟然压根没考虑到。

  • 有桌面,桌面有若干页面可以通过调用函数来动态创建或删除,下面有页面指示器(简单的小圆点组成)
  • 有应用,点击后可以加载对应的应用qml文件,并让桌面不可视,应用可视。同时考虑到现代手机上除了1*1的桌面图标外,还有m*n的组件。应用qml随便设计一个简单界面即可,方便测试,应用里添加了一个返回按钮(清除应用后台)
  • 有顶部栏,目前只显示时间,后续可以添加CPU温度等系统信息
  • Home悬浮窗,用于在任何应用界面返回到主界面(不清除后台应用)

        当初以为使用ui开发更方便,毕竟可以使用图形化工具。而qml虽然也有,但用起来很卡,而且如果qml里使用了类或者跨目录的qml文件,那么很多都无法显示出来。

        但后来觉得还是“对话式开发”比声明式开发、命令式开发更方便,人负责想象,AI负责生成。即便想象很贫瘠,AI也能自己生成令人较满意的UI界面,下图这个不算。

这个计算器只能看,不能用

3,整理

      当测试应用框架基本差不多,可以转正时,那么就清理原项目留下来的痕迹,把没有用到的代码能删就删 。这里只清理了qrc和main里用不到的资源,其他文件不要删除,一些具体实现细节还需要参考

        后面就可以参考先前代码中的关键部分,继续开发应用,做好一个删一个

4、设计应用

        在框架搭建好之后,接下来只需要专注于设计具体的桌面应用。比如此时此刻,只需要考虑modules/Calculator这个目录怎么设计,不必再关心桌面切换、应用切换等(前面已经搭建好了机制)

        由于是重开一个对话,那么原先关于应用的启动等机制AI是不知道的,比如下图,那么这些我们自己保留即可。

        如果在一个对话里,无论怎么问,都不能解决办法的话,最好重开一个对话,并且给出关键代码(不需要包括qml等),比如设计计算器时,表达式解析出现问题

        经过一系列人机对战,得到了一个计算器应用,忽略掉必要的bug外,它已经是合格的计算器应用了(按键排布得有些不顺手)。事实上如果是自己动手设计UI,我觉得自己很难设计出这种简洁大方的UI

 

 

二、开发板调试

1,上板 

       改了一下pro文件,现在可以在Qt上运行,方便等下连接开发板调试(话说应该把这个功能搞到CLion上)

 

使用Filezila传输给虚拟机

到虚拟机里,用虚拟机以前工程里的pro.user替换掉现在的,不然rsync还需要重新配(详情见上一篇)

然后配置工程,勾选桌面端是为了看看不同平台下有没有问题

显然遇到了一个小问题,难怪之前正点原子的例程源码里会有"./",当时嫌啰嗦就删了,现在看很有用嘛

遇到下面问题,后来发现是版本问题,我使用的是5.15.2,而正点原子是5.12.9(当初看错了,以为都是5.15)

        尝试编译5.15.2,有各种各样的问题,但最大的问题就是Ubuntu 16现在不支持了

        除此之外,有些Qt库还没有(交叉编译Qt源码跳过了,比如OpenGL)。想想还是算了,阉割一下也能用,在舍弃掉一些效果后,终于可以运行了

烧录到开发板上,开始有些问题,原桌面进程没有沙掉

        沙掉后重新运行(可以使用ssh传输命令沙掉进程)。唯一让我百思不得其解的是应用图标不见了,使用起来倒很流畅(毕竟应用和功能很少)

        CPU温度本来能正常显示的,但只要我在屏幕的一个地方按久了就自动变为零。这个算小bug,先放过它。

        温度显示这个功能是学原例程中desktop目录下的desktop.cpp文件的,它是通过访问用户空间里的驱动实现的,控制LED也同理。

这是现桌面的开销(很简陋所以开销小)

下面是原桌面,在例程源码中可以看到它在初次加载桌面时,实际上就把所有应用都加载了。如果不全部加载的话,开销应该会小一些。

又测试了一下,发现png是能显示的(右上角),同样的图片应用图标却不显示,那应该是打开的方式出了问题

        按照这个思路,觉得是应用图标的加载有问题,看到程序里的OpacityMask和QtGraphicalEffects,知道了问题所在,开发板使用的Qt库里是没有使用OpenGL的。

        去掉之后,图标可以显示,与预期一致,但我的圆角没了,先后试了不使用OpenGL的方法,还是不行(x_x)

        可是使用OpenGL,对于我这个一次也没能编译成功的loser来说,属实煎熬。

        好像还少了一个主菜单键,查了一下原因,也是使用了OpenGL原因,去掉使用OpenGL渲染阴影的代码就能正常显示了。此外开发板上的字库好像没有“🏠”这个字符,先用Home代替吧

2、设置启动脚本 

        配置启动脚本,需要编辑/etc/rc.local文件

vi /etc/rc.local

        脚本里的内容基本完善,开机后会运行/opt/Desktop这个程序,并设置为后台启动。由于暂时还没学如何改uboot或linux内核关于网络的设置,就用网络重启命令来把ip重置为设定的值

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.


echo 30000 >  /proc/sys/vm/min_free_kbytes
source /etc/profile
/opt/QDesktop >/dev/null 2>&1 &

# 网络重启
/etc/init.d/networking restart
exit 0

        网络重启要在桌面启动后面 ,如果放在前面需要加延时(sleep 3),不然桌面程序就不会运行。要注意,修改完成并保存后,要输入sync再重启,不然数据还在缓冲区里,直接重启会丢失

        注意到前面我们使用rsync调试,实际上会把编译后的桌面程序传输开发板的/opt/test/bin目录里,然后运行。如果想要调试一次就让开发板之后运行桌面程序,可以改一下rsync中传输的目录,把/opt/test/bin改为/opt,不过开发板原先的Desktop程序记得备份一下。

三、项目结构 

1,基础框架 

      接下来回头看看这个简单的项目构成,下面是此时理想中的项目结构,后续可能会根据需求改变,目前起指导作用

        业务逻辑的入口main.cpp这里,现在只注册了两个类,计算器类和系统检测类,后者目前只检测了CPU温度。这里没有花什么精力,是在原例程基础上删改得到的

        界面入口main.qml这里,在了解原例程中main.qml结构后,就重做了。把界面分成两个部分,一个是桌面容器,另一个是应用容器。初始状态只加载桌面,桌面的具体设计是在Desktop.qml里,应用的具体设计在AppPage.qml里。

        当点击桌面上的图标后,就把桌面容器变成不可视,然后加载应用的qml文件(创建Loader),并可视,这就是应用启动的逻辑。退出应用就是让桌面可视,此时要么关闭应用示例(清后台),要么让它不可视。实际上就是把桌面和应用都当成了某个界面,没有从属关系,只是简单的并列,把桌面当成某个“应用”也无妨。

        在上面两侧之外的是悬浮窗,这个位于整个界面的上层,确保无论是在桌面还是应用都不会影响它的显示。

        除了上面三个和界面相关的之外,下面就是界面逻辑了,目前有启动应用、关闭当前应用和关闭所有应用,其中关闭应用又分为清理后台还是不清理后台两种。

        启动应用这里,会先判断Loader里有没有这个应用,因为前面提到过,返回主菜单不清后台时,只会把这个Loader变得不可视,不会销毁它。如此,就避免了重复创建Loader实例。如果不存在,那么创建示例。

2,桌面

        桌面这里,界面分为壁纸、顶部栏和页面三个部分,壁纸可以用图片或者动态渐变、粒子效果等,这里只用了简单的渐变效果。

        顶部栏只是一块区域,具体的实现在TopBar.qml里

        页面这里分为页面本身(SwipeView组件)和页面指示器(下面的小圆点),由于使用过程中,Repeater这个组件在跨文件时出现了问题,这里没能把页面指示器分离出一个qml文件,只能在这里了留下了臃肿的代码。

        接下来就是数据模型和创建页面、删除页面的函数。前面提到,桌面和应用并不是从属关系,所以这里的数据模型并非应用本身,只是把应用的一些属性给列举出来,方便显示应用图标(由页面组件SwipeView加载)。

        但也并非与应用没有任何关系,这里保存了应用的一些信息,比如加载qml的路径、大小、类型等,只在点击应用图标时,才会加载应用本体,减少不必要的开销。

3,应用图标

        应用这里是分了两个qml文件,一个是决定应用图标长什么样,另一个是动态生成应用实例。

        AppPage.qml在这里属于后者,在点击桌面上的应用图标后,它会根据那个应用的信息(大小、类型、qml文件路径等)来加载应用

        AppIcon.qml在这里决定了桌面上的应用图标的基础通用样式——有图片,图片下面有应用名称,可点击

4,应用

        前面的只是应用图标,与桌面是从属关系,这个才是应用。modules这个目录里可以放各个应用,每个应用都是一个文件夹。目前这里只有一个计算器,计算器里分为界面和逻辑。

        为了模块化,界面可由多个qml文件共同构成,这里设计了计算器的按钮和计算器整体界面。应用界面是完全独立的,相当于一个新的桌面界面。

        为完成交互功能,界面文件(Calculator.qml)会嵌入C++的类,通过调用这个类里的各个函数来完成交互逻辑的实现。

        下面是交互逻辑的实现文件,是QObject的派生类,给qml提供各种接口使用

        具体的交互逻辑实现让人头都大

5,系统

        系统级应用,使用单例模式,一直在后台加载,可暴露给需要的组件。比如获取CPU温度、系统音量等。与前面应用开发里的交互逻辑实现差不多,提供各种接口

 

 

        源码暂时不发,因为现在还很简陋,只有一个计算器可以使用。而且由于先前是在正点原子例程改的,会有大量文件夹,有些乱,还没整理。应该不会等很长

        在Qt Creator的视角下是很整齐

        在CLion这就有些乱了(真实目录)

        目前搭建好了基础框架,后续可以在这个基础上开发更多应用。但应用图标不能圆角显示这个问题,可能真的需要OpenGL支持或者使用更高的Qt版本。嗯,想了想,现在这套开发流程虽然简陋,但可以胜任一些基础功能的开发,控制个灯还是没有问题的。

        嗯后续可以再搭建一套开发流程,使用imx6ull官方最新的uboot和linux,以及正点原子的根文件系统制作SD卡启动,然后再尝试编译6.8.1的Qt源码,开发6.8.1下的Qt桌面程序,再接着制作自己的根文件系统。由于前面的学习并没有涉及到更改uboot、Linux内核和根文件系统,所以只要把桌面应用程序和一些驱动模块移动到EMMC上,再改一些配置文件,就可以使用了(设备树可以不动)。

        我想想,如果这样的话就有了两套开发流程,一套是EMMC上,旧的开发流程,另一套是SD卡上的,新的开发流程,即便新的尝试失败了,至少还有EMMC上的作托底。


http://www.kler.cn/a/522639.html

相关文章:

  • 微服务入门(go)
  • 17 一个高并发的系统架构如何设计
  • Vue.js组件开发-实现下载时暂停恢复下载
  • Python学习之旅:进阶阶段(五)数据结构-双端队列(collections.deque)
  • 设计模式-建造者模式、原型模式
  • 为AI聊天工具添加一个知识系统 之78 详细设计之19 正则表达式 之6
  • java后端之登录认证
  • C# 添加、替换、提取、或删除Excel中的图片
  • C语言练习(28)
  • maven的打包插件如何使用
  • CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据)
  • 在做题中学习(81):替换后的重复字符
  • L30.【LeetCode题解】丢失的数字
  • 【无标题】TensorFlow、PyTorch、ONNX、TensorRT
  • 认知计算与 AI 大模型:数据仓库、数据湖与数据分析的变革力量
  • 《SwinIR:使用Swin-Transformer图像恢复》学习笔记
  • 深度解析:基于Vue 3与Element Plus的学校管理系统技术实现
  • LVGL+FreeRTOS实战项目:智能健康助手(lcd篇)
  • Java学习笔记(二十五)
  • Python面向对象编程实战:构建强大的 `Person` 类
  • CSS知识总结
  • zookeeper-3.8.3-基于ACL的访问控制
  • 私域流量池构建与转化策略:以开源链动2+1模式AI智能名片S2B2C商城小程序为例
  • Hive详细讲解-调优分区表速通
  • The Simulation技术浅析(二):模型技术
  • Python爬虫获取custom-1688自定义API操作接口