Qt6开发入门-环境配置与入门

安装

在线安装包可以去官网找,也可以这里下载:https://mirrors.nju.edu.cn/qt/official_releases/online_installers/ ,但提前需要在Qt官网注册账户。下载需要换源,命令如下:

1
qt-online-installer-windows-x64-4.9.0.exe --mirror https://mirror.nju.edu.cn/qt

安装时选择“个人使用”、“自定义安装”。建议选择安装目前最高版本的Qt6下的MSVC 2022 64-bit和MinGW 13.1.0 64-bit套件,选中Sources、全部Additional Libraries和Qt Debug Information Files。Build Tools中选择Qt对应的MinGW版本、Qt Installer Framework、CMake、Ninja和全部OpenSSL Toolkit。Qt Creator中建议选中Qt Creator、CDB Debugger Support、Debugging Tools for Windows、Debug Symbols和Plugin Development。大约总共需要30GB空间。

为Visual Studio 2022安装扩展“Qt Visual Studio Tools”,重启并选择“扩展”->“Qt VS Tools”->“Options”,在“Qt”->“Versions”中找qmake.exe。新建项目“Qt Widgets Application”,即可开始开发。要注意项目中的“符合模式”选项必须开启,否则编译不通过。Qt Designer在VS2022中的内嵌模式支持非常不好,有时能打开有时打不开,可删掉Qt Designer选项自己新建一个编辑器。

也可以使用Qt Creator新建项目,用Qt Creator打开项目时选择CMakeLists.txt,然后编译即可。编辑UI界面可用Qt Creator打开.ui文件,其编译后对应的文件在build目录对应编译模式文件夹下的\xxx_autogen\include\ui_mainwindow.h。

Qt也可部署在Linux上,但若缺少桌面系统,会缺少几个必要的链接库,缺啥补啥即可。

Windows上Qt打包可尝试windeployqt。

入门

程序结构

主程序文件main.cpp内容为:

1
2
3
4
5
6
7
8
#include "mainwindow.h"
#include <QApplication>
int main(int argc,char *argv[]){
QApplication a(argc,argv); //创建应用程序
MainWindow w; //创建窗口对象
w.show(); //显示窗口
return a.exec(); //运行应用程序 开始应用程序的消息循环和事件处理
};

窗口源程序mainwindow.cpp:

1
2
3
4
5
6
7
8
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),ui(new Ui::MainWindow){
ui->setupUi(this); //this为MainWindow类对象实例 setupUi创建窗口界面组件 以MainWindow为组件父容器
};
MainWindow::~MainWindow(){
delete ui;
};

窗口类定义头文件mainwindow.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui{
class MainWindow; //这里MainWindow是ui_mainwindow.h中定义的
};
QT_END_NAMESPACE
class MainWindow:public QMainWindow{
Q_OBJECT //使用Qt元对象系统的类时必须插入 可实现信号与槽、属性等功能
public:
MainWindow(QWidget *parent=nullptr);
~MainWindow();
private:
Ui::MainWindow *ui; //指向可视化设计的窗口界面
};
#endif // MAINWINDOW_H

例如拖拽一个Push Button,右键“转到槽…”可编写内容。也可直接设计器下方Signals and Slots Editor窗口中添加一条,发送者选择pushButton,信号选择clicked,接收者选择MainWindows,槽选择close。

在ui_mainwindow.h中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow{ //该类用于封装可视化设计的界面
public:
QWidget *centralwidget;
QLabel *label;
QPushButton *pushButton;
QMenuBar *menubar;
QStatusBar *statusbar;
void setupUi(QMainWindow *MainWindow){
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName("MainWindow");
MainWindow->resize(800,600);
centralwidget=new QWidget(MainWindow); //将MainWindow设为QWidget父容器
centralwidget->setObjectName("centralwidget");
label=new QLabel(centralwidget);
label->setObjectName("label");
label->setGeometry(QRect(130,140,411,181));
QFont font;
font.setPointSize(20);
label->setFont(font);
pushButton=new QPushButton(centralwidget); //将centralwidget设为QPushButton父容器
pushButton->setObjectName("pushButton");
pushButton->setGeometry(QRect(360,340,92,28));
MainWindow->setCentralWidget(centralwidget);
menubar=new QMenuBar(MainWindow);
menubar->setObjectName("menubar");
menubar->setGeometry(QRect(0,0,800,47));
menubar->setFont(font);
MainWindow->setMenuBar(menubar);
statusbar=new QStatusBar(MainWindow);
statusbar->setObjectName("statusbar");
MainWindow->setStatusBar(statusbar);
retranslateUi(MainWindow);
QObject::connect(pushButton,&QPushButton::clicked,MainWindow,qOverload<>(&QMainWindow::close)); //设置信号与槽的关联
QMetaObject::connectSlotsByName(MainWindow);
}; // setupUi
void retranslateUi(QMainWindow *MainWindow){ //设置界面各组件文字属性
MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow","MainWindow",nullptr));
label->setText(QCoreApplication::translate("MainWindow","TextLabel",nullptr));
pushButton->setText(QCoreApplication::translate("MainWindow","PushButton",nullptr));
}; // retranslateUi
};
namespace Ui{
class MainWindow:public Ui_MainWindow{};
}; // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H

Ui::MainWindow ui可访问窗口界面上所有组件,例如:

1
2
3
4
5
6
MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),ui(new Ui::MainWindow) {
ui->setupUi(this);
ui->label->setText("Qt6");
ui->pushButton->setText("关闭");
return;
};

在项目管理器中的子项目上右键添加新文件,类型选择Qt类的Qt Resource File,选择要添加到的子项目。添加一个资源前需要先添加一个前缀,例如icon等,在每个前缀下面添加文件,例如可在项目目录下新建一个images目录,下面放所有图片。

例如可以将若干Check Box放入一个Group Box中,在右侧对象查看器中能够看到层次。Qt Creator上方有几个小按钮:编辑控件、编辑信号/槽、编辑伙伴、编辑Tab顺序,此外控件中还有各种Layout和Spacer可尝试。例如在编辑伙伴视图中,点击某个Label并拖拽到某Line Edit控件上,形成伙伴关系,再例如将Label的text属性设为“姓名(&N)”,此时“&”将不显示,意为快捷键为Alt+N,按下后焦点将转向其伙伴控件,即Line Edit控件。

信号与槽初探

信号是在特定情况下被发射的通知,槽是对信号进行相应的函数。信号与槽的管理用QObject::connect实现,QObject是大部分Qt类的基类,一般可忽略。一个信号可连接多个槽,槽函数按照建立连接时的顺序依次运行。信号和槽函数带有参数时,要指明各参数类型,不用指明参数名称。多个信号可连接同一个槽函数,一个信号也可连接到另一个信号,信号与槽的参数个数和类型要一致。使用信号与槽的类中,必须在类的定义中插入宏Q_OBJECT。某参数不用时可用Q_UNUSED宏标记。

1
QObject::connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));

一种常用的使用示例:

1
connect(ui->spinNum,SIGNAL(valueChanged(int)),this,SLOT(addFun(int)));

例如拖入一个Check Box,右键转到槽选择clicked(bool)信号,在mainwindow.cpp中自动出现以下函数,并自行添加内容:

1
2
3
4
5
6
void MainWindow::on_checkBox_3_clicked(bool checked){
QFont font=ui->checkBox_3->font();
font.setUnderline(checked);
ui->checkBox_3->setFont(font);
return;
};

翻看ui_mainwindow.h中的setupUi函数,出现以下内容,表示搜索MainWindow界面所有组件,将名称匹配的信号和槽关联起来。

1
QMetaObject::connectSlotsByName(MainWindow);

相当于:

1
connect(chkBoxUnder,SIGNAL(clicked(bool)),this,SLOT(on_chkBoxUnder_clicked(bool)));

其中,槽函数命名格式为:

1
void on_<对象名>_<信号名>(<信号参数>);

将几个Radio Button放入同一个Group Box等容器中,自动改为互斥的。此时要为所有Radio Button连接到一个槽函数上,选择在mainwindow.h的MainWindow类的private slots部分手动添加下面定义,其中以do开头的槽函数一般认为时自定义槽函数。

1
void do_setFontColor(void);

在函数名上右键重构,选择在mainwindow.cpp中添加定义,并添加具体代码:

1
2
3
4
5
6
7
8
9
void MainWindow::do_setFontColor(void){
QPalette plet=ui->label->palette();
if(ui->radioButton->isChecked())
plet.setColor(QPalette::Text,Qt::blue);
else
plet.setColor(QPalette::Text,Qt::red);
ui->label->setPalette(plet);
return;
};

然后得自己关联:

1
2
3
4
5
6
7
MainWindow::MainWindow(QWidget *parent):QMainWindow(parent),ui(new Ui::MainWindow){
ui->setupUi(this);
//...
QObject::connect(ui->radioButton,SIGNAL(clicked()),this,SLOT(do_setFontColor()));
QObject::connect(ui->radioButton_2,SIGNAL(clicked()),this,SLOT(do_setFontColor()));
return;
};

为了给可执行文件添加图标,将图标.ico文件放在项目根目录下,新建xxx.rc文件,记事本打开添加文本:

1
IDI_ICON1 ICON "文件名.ico" 

然后在CMakeLists.txt中添加:

1
2
3
4
5
qt_add_executable(qttest2
WIN32 MACOSX_BUNDLE
...
xxx.rc
)

Qt对标准C++语言进行了扩展,引入了元对象系统MOS,所有从QObject继承的类都可利用MOS提供的功能。MOS支持属性、信号与槽、动态类型等特性。构建项目时,项目中头文件先被MOS预编译,可视化设计的窗口UI文件被用户界面编译器UIC转为一个C++源程序文件,.qrc资源文件会被资源编译器RCC转换为C++程序文件。用MOS、UIC、RCC编译各原始文件的过程称为预编译过程,生成标准C++语言的程序文件,被标准C++编译器编译和连接,生成可执行文件。

CMake文件

CMakeLists.txt内容如下,一般不需要自行修改,只有用到Qt某些附加模块时需要改动qt_add_executabletarget_link_libraries

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
cmake_minimum_required(VERSION 3.19) #需要的CMake最低版本
project(qttest2 VERSION 0.1 LANGUAGES CXX) #项目名 版本号 编程语言C++
find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets) #查找和导入Qt某个模块
qt_standard_project_setup()
qt_add_executable(qttest2
WIN32 MACOSX_BUNDLE
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
res.qrc
logo.rc
)
target_link_libraries(qttest2 #设置连接时用到的Qt模块
PRIVATE
Qt::Core
Qt::Widgets
)
include(GNUInstallDirs)
install(TARGETS qttest2
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
qt_generate_deploy_app_script(
TARGET qttest2
OUTPUT_SCRIPT deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})