1.前言
前面的几个章节,我大致介绍了Qt的使用方法,突然面对这么一大堆东西,可能你会觉得有点难以接受。
不过这也正好体现了本系列教程的目的,让每一篇都有一定的含金量。
所以本节,我就将带大家用Qt制作一个天气预报的项目,让大家熟悉熟悉Qt的基本开发流程。
本项目的总体逻辑并不复杂,更主要的还是学习一下常用控件的用法。
前面介绍Qt库时我就说过,通过请求一个天气预报API,获取其中的天气预报信息,为json
格式,然后我们再解析这个json格式的数据,显示到控件上即可。
有思路的话可以自己先写写看,它主要用到了Qt网络库,前面章节可能没有讲到过,所以本章也会顺带介绍Qt网络库的使用。
最终成品大致如下:
看起来还算不错吧!
2.建立项目
因为我个人习惯于使用vs,所以这里是在vs里面进行开发的,建立流程前面章节已经提到过了,这里不再赘述。
只需要注意一下我这里的项目名为Weather
、并且选择的是widget
类型就可以了:
然后还要下载本项目的资源文件:weather-res
下载解压后文件如下:
其中一个是包含各种图片的文件夹res
,一个是中国城市ID大全,并且为json
格式版本,这是我们在项目中要用到的,你需要将其复制到你自己的项目文件夹中去:
至此,我们的前期准备工作就完成了。
3.界面开发
3.1 去除标题栏
首先我们还是先来把界面调整好,比如你发现没,这个软件是没有标题栏的。
去除标题栏的原因很简单,因为我们希望自定义标题栏的样式,如果保留默认的,就会感觉整个软件不那么的好看。
所以首先第一步,我们先来去除这个标题栏:
setWindowFlag(Qt::FramelessWindowHint);
方法就是调用上面这个函数:
这个函数用于设置当前窗口的标志信息,参数为FramelessWindowHint
,即无标题类型。
更多类型可以参考文档,前面已经教过怎么查找了。
标题栏是没了,但又出现了一个问题,如果此时你运行程序,你就会发现你无法移动、退出程序了。
因为这些都是标题栏的作用,为了让我们的窗体也有这个功能,我们就需要重载鼠标移动、点击、释放这三个函数,也就是自定义:
//重写鼠标事件
void mousePressEvent(QMouseEvent* e);
void mouseMoveEvent(QMouseEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
这些函数是可以在文档中找到的,在保护属性函数栏中:
可以看到它们前面的virtual
关键字,这是虚函数,可以被我们重写,所以就有了我们这里的代码,我们就是想要重写鼠标事件的回调函数:
然后我们需要考虑一件事情,那就是鼠标是如何拖动窗口的:
- 鼠标左键点击
- 鼠标移动,窗口跟着鼠标移动
- 鼠标左键松开,窗口停止移动
因此我们就需要两个变量来保留鼠标左键点击时的状态:
同时我们使用这个QMouseEvent
类时,还需要包含上面这个qevent.h
这个头文件才行:
#include<qevent.h>
QPoint m_prePoint; //记录鼠标左键点击时的位置
bool m_islBtn; //记录鼠标左键是否是按下状态
保存的方式如下:
我们可以通过传入的鼠标事件对象e
上的函数button
来得到当前按下的是什么,如果为鼠标左键,那么它与Qt::LeftButton
这个枚举量的值就可以进行且运算,并且为1
。
这里涉及枚举、以及且运算,枚举可以参考本站的这篇文章:枚举与枚举类,且运算可自行浏览器搜索,这是比较基础的内容。
保存的方式就是通过上面的那两个变量进行的,将m_islBtn
设置为true
,并且计算一下当前鼠标点击位置距离窗口左上角的向量值。
通过e->globalPosition().toPoint()
函数返回鼠标相对于整个电脑屏幕的坐标,然后减去窗口的左上角相当于整个电脑屏幕的坐标:frameGeometry().topLeft();
,就是一个向量计算,得到的结果就是鼠标位置相对于当前应用窗口的坐标。
向量减法,初中学的,还是高中?这里就用上了!
然后你还看到了我们同时写了一个鼠标右键按下时要弹出的菜单,也就是俗称的右键菜单。
这个后面再提。
之后我们还需要在鼠标左键释放的时候,去除这个状态:
代码:
void Weather::mouseReleaseEvent(QMouseEvent* e)
{
if (e->button() & Qt::LeftButton) {
m_islBtn = false;
}
}
我们这个变量的目的就是确定当前鼠标左键必须是按下的状态才将其赋值为true
。
最后就是鼠标移动时的回调函数了:
代码同样简单,就是确定当前鼠标左键是按下的状态,我们才移动。
if (m_islBtn) {
move(e->globalPos() - m_prePoint);
}
移动就是通过move
函数来做到的,它需要的是一个窗口左上角要移动的目标点。
而这个点我们就可以通过向量减法得到:
上面是随手画的一个图,外面黑框代表屏幕,里面黑框代表窗体。
我们的m_prePoint
变量存的值,就相当于向量OA-OF得到的向量FA
。
当我们鼠标移动时,就可以通过e->globalPos()
或者e->globalPosition().toPoint()
来得到B点的全局坐标。
这两个函数,前者是老版本的,后者是新版本的,目前都可以用,但官方推荐使用后者。
这里的全局坐标是相对于屏幕左上角而言的。
所以这里的e->globalPos() - m_prePoint
就相当于:OB-FA
。
我们现在需要的是C
点坐标,也就是OC
,而OC=FC-FO
。
而FC=AB=FB-FA
。
所以就有OC=FB-FA-FO=FB-FO-FA=OB-FA
。
就此得到了C的坐标等于OB-FA
,即鼠标移动点的目标位置减去前面计算得到的向量。
这里涉及到的都是点的计算,Qt之所以能够这么计算,是因为这个点类,重载了加减运算符,这就是Qt的方便之处。
而如果没有重载加减运算符,那你就得分别对x、y坐标做运算,很麻烦。
此时你运行程序就会发现,无论你点击哪里,都可以拖动窗口了。
3.2 美化页面
然后就是美化页面,一般有两种方案。
- 调色美化,也就是输入rgba这些颜色数值来美化页面,需要有一定的美术功底,对色彩搭配有一定的了解。
- 图片美化,直接找现成的图片贴到窗口上。
两种方式各有优缺点,我们这里比较简单,直接使用图片美化,而图片就是前面让大家下载的资源中,res文件夹下的内容。
但可以看到的是,里面的图片非常之多,有几十个,所以我们这里使用资源管理器来添加:
这里通过Add Prefix
添加了两个目录,并将原本的Weather
改为了img
,这样做的目的是将不同类型的图片放在不同的地方,方便管理。
名字是可以直接在Prefix
后面的输入框中进行修改的。
然后分别点击上方的目录,然后进行添加文件:
其中img
中存放的是res
文件夹下的图片,而day
与night
则直接存放的是res/day
与res/neight
这两个文件夹下的所有图片。
记得Ctrl+S
进行保存。
完成了资源文件的添加之后,我们就可以通过Qt的设计工具来设计我们的页面了。
首先是背景图片的添加: