如何用qml(Qt Quick)做界面,用C++(Qt)实现业务逻辑?

本人是Qt初学者,正在写一个会计小软件(Linux桌面版)。看了Qt的介绍,觉得用qml(Qt Quick)做界面非常机动快速,但是qml(Qt Qu…
关注者
357
被浏览
210,818
登录后你可以
不限量看优质回答 私信答主深度交流 精彩内容一键收藏

LINUX-Environmental-programming/天气预报查询系统 at master · zhengzebin525/LINUX-Environmental-programming

项目的代码文件我放在了自己的github里面,以上是链接,想要的可以自行下载,以下说明最好参看代码学习,效果更好。

先来看看最后能做成的样子吧。

OK,先来讲讲最初设想的大概流程和思路吧,我用的是C++语言,开发平台用的是QT,这是可以跨平台做界面开发的软件。

运用的点大致有:做界面用的组件,布局,样式,定时器,网络, 事件

做这个项目的前提是必须要对QT和C++有一定的熟练度,所以有些太基础的东西比如新建工程这一些我就不会细讲。

我的项目步骤细分的话可以分为七步:(步骤没有绝对的先后之分,看自己思路习惯)

第一步:规划好ui界面布局;

第二步:界面上方显示系统日期和系统时间;

第三步:可查询天气,利用接收cJSOn数据并解析,分别将当天温度、感冒指数、各天的日期、高低温以及天气图片输出;

第四步:将各控件变透明并点击右上角“皮肤”按钮更换窗口背景图片;

第五步:最下端滚动显示“你好,这是天气查询显示平台”;

第六步:通过左上方输入框输入城市,点击“搜索”后更新ui界面各天气信息;

第七步:点击最右上角“ X ”,退出ui界面;

以下就是步骤的详细思路:

第一步:规划好ui界面框架

我创建的工程名为 WeatherQuery ,主文件 main.cpp weatherquery.cpp weatherquery.h weatherquery.ui

构思往往是做项目的第一步,下手之前,花了点时间整理了下思路,并把ui界面大致规划好了,如下:

相信只要对QT有些基础的同学要完成这一步一定不难,先布局好了大概样子,记得要将各个控件对命名号名字,以免混淆,而暂时没想到的细节可以后面慢慢补上。

第二步:上方显示系统日期和系统时间

这一步需要用到定时器来获取系统日期和时间,所以到这三个头文件:

需要在文件weatherquery.h的类中添加一个定时器对象:

在weatherquery.cpp的构造函数中,打开定时器并设置好定时时间,再将定时器信号与槽函数关联,这样就是每当过了xx秒,系统就会自动执行一遍槽函数

而槽函数中就写了自动获取系统日期和时间的代码,并把获取到的信息显示在ui界面对应的控件上,这个的显示时间和日期的控件我用了LCD Number这个控件;

记得槽函数要在weatherquery.h的类中要进行声明哦,声明方式也可以不用手打,有快捷方式,在Refactor中选择“添加private slots声明”就可以了。

第三步:接收cJSOn数据并解析

这个是较为核心的一步,因为各个天气的数据,都是从cJSON数据的得到的,而这个cJSON是怎么来的,网上有一些专门查询天气指数的服务器,比如说下面这个:

wthrcdn.etouch.cn/weath

只要在浏览器网址上输入这个地址,后面的101280101是我自行加上去的,此ID是广州城市的ID,随后你将得到的是广州市的天气指数的CJSON数据,里面的内容是这样的,这就是cJson数据,你需要的天气数据,都在里面了:

这样如果比较难看,可以将内容copy下面,放在一个记事本中:

如果看不懂,可以借助一些工具进行解析,比如cJSON在线视图查看器,这个工具百度一下就有了:

​在“JOSN数据”中复制黏贴进cJSON数据,然后点击“视图”,就能全面清晰看到天气数据,如下图:

当然了,以上的操作,我们都要用代码来实现,包括接收cJOSN数据,解析并获取自己想要的某一个天气指数等。

在接收到cJSON数据之前,当然先要在向远方的浏览器服务器发送网址请求。

下面这个就是获取天气预报信息的服务器地址了:

http://wthrcdn.etouch.cn/weather_mini?citykey=xxxxxxx

后面的“xxxxx”就是对应城市的城市ID(不知道你所在城市的ID可以上网查,每个城市的ID都是固定的)

在这里,我们称之为发送请求报文,这个HTTP网络操作,不借助浏览器,用代码来实现,首先需要用到这几个网络头文件:

又因为需要解析cJOSN数据,又需要这几个头文件:

还有要注意的一点是,因为要用到网络,所以必须要在weatherquery.pro中接入网络模块QT += network,按下面这么直接添加“network”就可以了:

​其次需要在.h类中定义一个网络管理器对象:

因为我们需要一运行ui界面就显示出一个默认城市的天气指数,所以需要在构造函数写代码,记住,构造函数里的程序一运行自动执行一次,只有一次!

我们设计的思路就是:

当我们在ui界面左上角输入城市后,点击搜索按钮就会进入另一个函数中再次发送请求报文,获取新的cJOSN数据,将数据解析显示出来,不过由于搜索框的代码还没写,就先搁置了,先写运行默认城市的代码。

先在构造函数里发送一个请求报文:

一旦这个报文发送出去了,manager管理器就会产生一个timeout信号出来:

这个关联操作的意思是,一旦manager管理器发送了timeout操作,就自动执行解析CJSO数据的槽函read_cjson(QNetworkReply*),槽函数都是自定义函数,在这个槽函数中,这个需要传一个参数,传什么参数呢,传的就是接收回来的cJOSN数据。

这里有一个小陷阱,一般思路都是先发送报文再关联槽函数,实际上,关联操作要在发送报文操作之前,原因很简单,如果在需要多系发送报文的情况下,要是在你发送报文的期间,上一次发送的报文已经有cjOSN数据传回来了,如果你的关联操作在后,那就不能执行解析cJOSN数据的函数。

所以正常应该都是这样的:

这里的城市ID就先固定了广州,默认一运行就是广州的天气指数。

接下来就是写你的用来解析接收回来的cJOSN数据的解析槽函数read_cJjosn(QNetworkReply *reply)了。

值得一提的是,一切接收回来的cjson数据,都会被放在QNetworkReply这个类中,只要在这个类中提取就可以了,所以我们才需要将传参定义QNetworkReply类型,这样cJOSN数据的地址就放在指针reply中了。

接下来,开始写代码,开始解析~~~~

好了,如果不信的话,可以将接收回来的cjosn数据通过qDebug打印出来,不过因为是qDebug打印的,所以打印出来的cjosn中会有很多的转义字符,这个如果用cjOSN在线视图查看器是看不出个123来的。

Ok.接下来开始解析,何为解析呢,就是在看起来乱的像条蛇的的cjosn数据中挑选出你想要的某一个确定的数据。

我们以下面的图来边看图边写代码,这样会对思路更加清晰:

​下面的代码,都要配合上面的图去看,这样一看就能理解为什么代码要这么写了:

由于forecase这个第二子根是一个数组,所以直接在数组中寻找:

这样,就可以在ui界面上显示日期,城市等信息了,但是这样还不够,要知道,我们设计的ui界面上还有显示各种高温、低温、风向、天气类型和相配的图片等,所以就有了下面的代码:

​上面红色框框的,就算根据不同的天气类型配合显示不同的天气图片了,因为我们解析出来的天气类型,都放在了type这个变量中,将这个变量作为函数传入WeatherType()函数中,函数就会根据type的内容返回一个字符串,这个字符串中就包含了需要显示的图片信息,利用返回值typemsg就可以直接显示对应的图片了,因为WeatherType()里面是这样写的:

各种天气图片也一并放在了链接里的工程中了。

因为要显示今天,昨天,明天,后面的天气指数,代码就有点多,不过实现的方法手段都是一样的,就不写下去了。

第四步:将各控件变透明并点击右上角“皮肤”按钮更换窗口背景图片

既然是背景图片了,那么一定要把控件设置成透明才行,否则的话,插入的图片会直接掩盖点整个界面,那就很尴尬了。

既然要把整个ui界面的控件变透明,那就要在整个ui界面的整体窗口进行设置,点中窗口空白部分(切记不要点到控件),右击选择“改变样式表”,然后点中“添加颜色”:

这里要注意的一点是一定点中如上图的紫色圆圈,这样才会有一系列样式选择项出来,在弹出来的样式选择项中选中“background-color”,意为选择背景颜色,然后会弹出来下图这样的一个颜色选择框:

看到Alpha通道那个选择项了吗,那就是设置透明度的地方,将其设置为0,整个ui界面的控件就变透明了,为我们通过插入背景图片改变ui界面的背景打通了一条路。

接下来,我们就可以插入背景图片了,在一开始的时候,我就在ui界面放了一个Push按钮控件:

就是图上那个红色的圈圈,那这个按钮的背景为什么变成了一件衣服的样子,那是因为我在这个按钮上插入了一张背景图片嘛。

这个相当简单,就点中那个按钮,右击“改变样式表”,如下图那样,一样要点中那个下三角的小标签哦:

在弹出来的样式选择框中选择“background-image”,然后就会弹出一个下图的资源文件框:

里头就有我找来的各种图片,包括那张衣服图片,选中,点击“OK”即可,样式编辑表就变成了下面那样:

虽然编译运行的时候,确实按钮的背景颜色变了,但是此外还需要考虑另外一点,按照逻辑来说,为了更准确具备一种“按下”的感觉,应该是鼠标一点击按钮,按钮的颜色就要改变一下,以此来营造一种有按钮按下的假象,因此,需要在“编辑样式表”中进一步如下的代码设置:

​Ok,这样运行时候就会有“按下”按钮背景图片改变的样子。

然后进行更改整个ui界面背景图片的大操作:

依旧是那个皮肤按钮,右击,选择“转到槽”,选中下图的clicked()单击信号函数,这个信号函数的意思是:一旦点击了按钮,就会执行槽函数一次,点击N次,槽函数就执行N次。

​点击“OK”,在跳转出来的槽函数中写入代码:

此处,通过按钮更改窗口背景的操作,完成,真实的效果,运行试一下就知道了。

在讲第五点的时候,有个地方如要提醒一下,就是上文几次讲到的资源文件,所谓资源文件,就是存放了各种资源的文件,很明显,我在这个资源文件下放的是一个图片文件夹。

因为这个资源文件new/prefix1/images是我一开始就放入工程中,所以一点开就有了,那么如果从一无所有中开始添加资源文件呢,下面就大概讲讲:

点击工程文件,右击“选择添加新文件”,如下图:

在弹出来的新建文件选择框中QT模板中的“Qt Resource File”,意为添加QT框架的资源文件,如下图,先点击“choose”,然后命名即可,我之前的命名是image,为了避免命名重复,就叫“aimages”吧,依次“下一步”、“完成”即可。

这样就在“资源”工程文件中见到新建的images.qrc文件,这个就是新建的资源文件,如下图,记得要把找到的图片文件夹拉进工程文件中哦,要不然资源文件可上哪儿去找图片?

点击“添加”,并选择“添加前缀”,这样就把放图片文件夹路径加了一个“new/prefixs”前缀;再点“添加文件”,再“打开文件”框中找到放图片的文件夹,按“ctrl”+A讲所有图片添加进来。

​看,然后图片资源就如下图那样进来了:

​这样就可以在编辑样式表中“添加文件”中看到有资源文件的存在了:

曾经发生一个状况,就是资源文件中忽然找不到资源文件了,并且编译出现以下错误:

:-1: error: cannot open output file debug\WeatherQuery.exe: Permission denied

解决办法很简单:进入任务管理器,将程序进程关掉,再重新运行,因为有可能是后台有Qt程序的.exe在运行,关掉就行了。

第五步:最下端滚动显示“你好,这是天气查询显示平台”

在做这一步之前,我重新写了一个QT工程RollTest,里面的功能就只是将一串字符串在窗口中从右到左滚动显示而过,里面的头文件rolltest.h和源文件rolltest.cpp,界面文件rolltest.ui都在WeatherQuery工程文件中都可以找到(因为这几个文件都是后面移过去的,下文会讲)。

因为这样的滚动操作需要用到绘图工具,所以rolltest.h中需要用到这几个头文件:

首先在rolltest.h中,创建几个私有对象:

然后在rolltest.c的构造函数中,一运行就自动执行一遍以下的构造函数:

那槽函数pushButton_clicked()中的功能就相当简单了,就是不断改变字符串的显示坐标,以此来产生不断滚动的现象,如下图:

​其中update()的作用就是不断刷新窗口,只有不断刷新了,窗口内字符串的移动状态新状态才会被不断更新显示,同时,这个函数内部,就有自动调用PaintEvent()绘图事件函数的代码,而这个绘制事件函数,我们就用来写滚动显示的正式代码,废话少说,看图:

​下面还有一个小小的操作,我们知道下图的rollStr中存放的是要进行滚动的字符串,我们要把这个变量变得可以进行由外部进行赋值,即通过WeatherQuery工程中的文件来进行设置。

​如下图进行右击,选择变成Settter成员变量:

​一旦rilltest.cpp中出现下面的函数,那说明就是变量改变成功了,此字符串要赋值成什么句子,可有外部自由决定。

​好了,到这里,那么滚动显示的代码就写好了,不过这里要提醒一下,这是我们重新开一个工程rolltest写的代码,并没有写在天气预报查询工程WeatherQuery里面,所以我们要做的,就是移植过去,将rolltest工程中的rolltest.h,rolltest.cpp,rolltest.ui三个核心文件复制粘贴到天气查询工程WeatherQuery中,复制完成后还要注意还要在工程里用“添加现有文件”添加进入哦。

然后,就在WeatherQuery的UI界面中,找一个空白地方,放置一个“Widget”窗口控件

​为什么要用这个呢,这相当于一个容器,将我们刚刚复制过来的几个rolltest文件固定在里面执行,这样,字符串滚动显示就被固定在了这个容器限制这个地方,字符串不会滚动着滚动着就跑到其他地方去,此外还有一个原因,因为我们要把这个Widget窗口控件提升,一旦涉及提升操作,大部分都是用这个Widget控件的。

​然后就会出现一个“提升的窗口部件”这个框,按下图进行操作:

​最后,点击”添加“,在点击“提升”即可。

一旦提升完成,那么这个Widget窗口控件的类型就不再是Widget类型,而是下面图这个类型了:

​这样就行了,不用再写代码了,因为Widget控件已经提升为了“RollTest”类型了,RollTest中执行什么功能,这个Widget控件就会执行什么功能,没错,RollTest中执行的是字符串滚动功能,那这个Widget控件就会执行字符串滚动功能。

好了,如果细心,就会捕捉到一个问题:这个滚动显示要显示的句子,到底该怎么决定呢,嗯,没错,这要解决一下;

因为我们已经把rolltest.cpp中的StringStr变量变成了可以进行外部赋值,那我们就外部赋值哦,这里说的外部赋值指的是由rolltest.cpp这个文件以外的其他文件进行赋值,看图就懂了:

​第六步:通过左上方输入框输入城市,点击“搜索”后更新ui界面各天气信息

UI界面中我插入了一个输入框,所谓输入框,就算可以直接输入文字内容的组件,而且我在输入框中靠左侧又添加了一个搜索按钮,如下图:

​然后按单击信号形式转到槽函数,因为那个“放大镜”是按钮组件,设置成单击信号的形式就代表着每当输入城市名字,按下搜索按钮后,就会调到槽函数,执行如下图的程序:

此处的难点在于红色框框,为什么这条代码就可以得到对应城市的ID号呢,因为我们用到了MAP容器,需要用到头文件:

而且需要在.h函数中添加对象:

​在构造函数中:

​这个citykeys.txt是网上找来的比较全的城市ID文本资料,我放在了build-WeatherQueryDesktop_Qt_5_7_0_MinGW_32bit-Debug文件夹中,要把上面的代码,一步一步调试打印出来,就会很好理解从字符串解析出字符串解析这种操作的原理了。

第七步:点击最右上角"X",退出ui界面

这是七个步骤中最省时间的一个部分,直接点击"X",右键转到槽函数,以单击信号的形式打开,在跳转到的槽函数中,写关闭代码就行。

​这只是一步把界面窗口隐藏的代码而已,并不是真的关闭,好吧,我承认这一步做的很随便,其实应该是在槽函数中关闭各种各样的文件,或者直接写强制关闭UI界面运行进程的代码即可。

发布于 2022-07-28 23:58 ・IP 属地广东