初学Qt的一点小笔记
最近的大作业需要用 C/C++
的技术栈实现一个图形化界面,Qt
作为C++图形化框架久负盛名,正好借着这个写大作业的机会学习一下这个应用广泛的框架。
Qt的安装
现在比较新版本的Qt貌似都不支持下载离线安装包了,受制于网络环境,在线安装的体验并不是很好。为了比较顺利的完成安装,使用老套路——国内镜像。清华大学就提供了Qt在线安装的镜像,具体的使用说明参照镜像的这篇帮助,在下载之前记得注册一个Qt的账号。
版本的选择
现在Qt
最新的版本已经来到了Qt6
,虽然现在Qt5
仍然十分的流行,网上大部分的资料与教程都是采用Qt5
写成的,我最后还是选选择了Qt6
,理由主要有以下三点:
- 工程并不是很复杂,而且开发的周期很长,即使在中间遇到了一些新版本的玄学问题,我也有比较充足的时间来解决或者避开问题
Qt6
开始完全转向cmake
管理项目,而我的这个大作业“恰好”就是采用cmake
管理的Qt6
是新版本,以后开发的时间还很长,稳定的开发环境还不是我现在需要的,学习的人还是应该积极的跟踪新技术(当然只是我自己的想法)
编译器的选择
我在Windows
平台上进行开发,虽然在之前学习过程中MinGW64 GCC
是我更常用的编译器,但是他毕竟是一个移植的编译器,而不是“官方”的编译器,我选择了MSVC
作为这次项目的编译器。
这里还有一个理由是我正在大力推进
WSL
在我日常开发中的使用,我正在把我所有的C/C++
项目都迁移到WSL
中进行开发,在Windows
中我已经不保留MinGW64
编译器了。
预处理的使用
在这次Qt
开发中我用到了两个预处理器——moc
和uic
,前者服务于Qt
的元对象系统(Meta Object System),后者负责与将Qt Designer
生成了*.ui
文件转换为编译器可以编译的ui_*.h
文件。这里重点说说前者,Qt
的元对象系统是Qt
信号和槽机制的基础,所有需要用到信号槽的类都需要继承QObject
这个基类,同时在类里申明Q_OBJECT
这个宏,而且,这个头文件还得被moc
预处理器预处理为moc_*.cpp
之后才能被编译器所编译,否则就会报LNK2001
连接错误,提示有三个函数无法找到定义,
@errorMsg.obj : error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall errorMsg::metaObject(void)const " (?metaObject@errorMsg@@UBEPBUQMetaObject@@XZ)
errorMsg.obj : error LNK2001: unresolved external symbol "public: virtual void * __thiscall errorMsg::qt_metacast(char const *)" (?qt_metacast@errorMsg@@UAEPAXPBD@Z)
errorMsg.obj : error LNK2001: unresolved external symbol "public: virtual int __thiscall errorMsg::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@errorMsg@@UAEHW4Call@QMetaObject@@HPAPAX@Z)@
在我这次的工程中,需要以下设置才能让moc
预处理器正确工作:
- 在
CMakeLists.txt
文件中需要定义set(CMAKE_AUTOMOC ON)
- 在包含这个头文件的地方需要将头文件的名称改为预处理之后的名称
moc_*.cpp
,如下图所示
Qt Designer
在一开始我对于这个软件的使用是比较迷茫的,没有搞明白哪些内容是在Designer
中完成的,哪些内容是在代码中完成的,在代码中是如何访问控件的。
这里需要说明的是,我是用
CLion
作为IDE开发C/C++
项目,在这里Qt Designer
是作为外部工具存在的。
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
ui = new Ui::MainWindow;
ui->setupUi(this);
}
那个名叫Ui
的命名空间让我迷茫了一阵子,在那个空间中也有一个和当前创建的UI类名字相同的类,我以为这是单例模式之类的高级设计模式,在研读了几篇博客,查看了UIC
处理器生成的头文件之后,我才意识到这是两个处在不同命名空间但名字相同的类,在Ui
命名空间中的那个类就是*.ui
文件中定义了那个界面,可以通过这个指针来访问我们在Qt Designer
中定义的那些控件。
Qt Property Animation
QPropertyAnimation
是Qt
自己实现的一个简单实用的动画框架,在这次开发中,我使用这个框架实现了对QGraphicsItem
这个对象的动画。这里主要的问题是,QGraphicsItem
这个类并没有继承QObject
,然而QPropertyAnimation
这个动画框架所作用的对象必须是一个继承自QObject
的对象,而且需要实现动画的属性必须注册Q_PROPERTY
,根据文档的说明,我定义了这样的一个类:
class BusItem: public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos WRITE setPos)
public:
explicit BusItem(const QPixmap& pixmap);
};
这个类多重继承了QObject
和QGraphicsPixmapItem
,这样既可以被QPropertyAnimation
所作用,也可以像正常的QGraphicsItem
一样被添加进QGrphicsScene
并设置各种属性。
而Q_PROPERTY
这个宏给Qt
的类型系统注册了一个类型为QPointF
名叫pos
的变量,这个变量的读通过调用pos()
函数来实现,这个变量的写通过调用setPos()
函数来实现,这个变量也就是我需要设计动画的变量。
这句代码给我的感觉像是在C#中的
set
和get
两个访问器。
2021 - 2024 © Ricardo Ren, 由 .NET 8.0.10 驱动。