学习资料:2019年最新QT从入门到实战完整版|传智播客
什么是Qt Qt是一个跨平台的C++图形用户界面应用程序框架。
1991年,Qt最早由奇趣科技开发。
Qt的应用案例:
Linux 桌面环境 KDE
WPS Office 办公软件
Skype 网络通话
Google Earth 谷歌地图
VLC 多媒体播放器
……
下载安装Qt Qt按照不同版本发行,分为商业版和开源版。
可以从清华大学开源软件镜像站 下载。
创建Qt项目 打开Qt Creator,点击New Project。
在New Project对话框中选择Application—Qt Widgets Application,填写项目名称,类信息基类改为QWidget,创建界面不勾选,完成。
新建的项目中自动生成了.pro
文件,main.cpp
,和widget.cpp/.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 01 _FirstProject.pro#------------------------------------------------- # # Project created by QtCreator 2020 -06 -17 T11:43 :06 # #------------------------------------------------- QT += core gui # 加载的模块,需要时在此手动添加 greaterThan(QT_MAJOR_VERSION, 4 ): QT += widgets TARGET = 01 _FirstProject # 生成的程序名 TEMPLATE = app # 应用程序模板 # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line . # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0 .0 SOURCES += \ # 源文件 main.cpp \ widget.cpp HEADERS += \ # 头文件 widget.h
1 2 3 4 5 6 7 8 9 10 11 12 13 main.cpp #include "widget.h" #include <QApplication> int main (int argc, char *argv[]) { QApplication a (argc, argv) ; Widget w; w.show(); return a.exec(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 widget.h #ifndef WIDGET_H #define WIDGET_H #include <QWidget> class Widget : public QWidget{ Q_OBJECT public : Widget(QWidget *parent = 0 ); ~Widget(); }; #endif
使用新建向导还可以创建C++ Class等文件,.pro
项目文件中会自动添加相关的文件名。
头文件:
在widget.cpp
中Widget类的构造函数中创建新按钮:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Widget::Widget(QWidget *parent) : QWidget(parent) { QPushButton *btn = new QPushButton; btn->setParent(this ); btn->setText("Button1" ); QPushButton *btn2 = new QPushButton("Button2" , this ); btn2->move (100 , 100 ); resize(600 , 400 ); setFixedSize(600 , 400 ); setWindowTitle("First Window" ); }
Qt的窗口坐标:
左上角为原点(0, 0),向右X坐标增加,向下Y坐标增加。
使用QDebug输出调试信息 头文件:
输出调试信息:
对象树 Qt中对象的终极基类是QObject
类,它以对象树的形式组织。
当你创建QObject
对象时,构造函数会接受一个QObject
指针parent
,父对象指针。创建的新对象会被自动添加到其父对象的children()
列表。
父对象析构时,children()
列表中的所有对象也会被析构。
Qt的对象树机制一定程度上自动解决了内存回收的问题。为了避免出现奇怪的错误,Qt鼓励在堆上直接创建对象,并在创建时就指定parent
。
信号和槽 信号槽是Qt的重要机制。
所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。
connect()
函数的最常见形式由四部分组成connect(sender, signal, receiver, slot)
,分别为信号的发送者、信号、信号的接收者、槽函数(即接收到信号后需要调用的函数)。
利用系统自带的信号与槽(查阅帮助文档),可以在Widget::Widget()
中添加以下代码:
1 connect (btn2, &QPushButton::clicked, this , &Widget::close );
该行代码使得当按钮2被单击,窗口关闭。
自定义信号和槽 在项目下新建类,继承自QObject
类(使用自动回收机制)
场景:当老师饿了,学生请老师吃饭。
sender:老师
signal:饿了
receiver:学生
slot:请老师吃饭
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 teacher.h #ifndef TEACHER_H #define TEACHER_H #include <QObject> class Teacher : public QObject{ Q_OBJECT public : explicit Teacher (QObject *parent = nullptr ) ; signals: void hungry () ; public slots:}; #endif
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 student.h #ifndef STUDENT_H #define STUDENT_H #include <QObject> class Student : public QObject{ Q_OBJECT public : explicit Student (QObject *parent = nullptr ) ; signals: public slots: void treat () ; }; #endif ----- student.cpp void Student::treat () { qDebug() << "请老师吃饭" ; }
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 widget.h #include <QWidget> #include "teacher.h" #include "student.h" class Widget : public QWidget{ Q_OBJECT public : Widget(QWidget *parent = 0 ); ~Widget(); Teacher *te; Student *st; void ClassOver () ; }; ----- widget.cpp #include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) { te = new Teacher(this ); st = new Student(this ); connect (te, &Teacher::hungry, st, &Student::treat); ClassOver(); } Widget::~Widget() { } void Widget::ClassOver () { emit te->hungry(); }
重载时的自定义信号和槽与信号连接信号 添加重载函数
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 teacher.h void hungry () ; void hungry (QString foodName) ; ----- student.h void treat () ; void treat (QString foodName) ; ----- student.cpp void Student::treat (QString foodName) { qDebug() << "请老师吃" << foodName.toUtf8().data(); } ----- widget.cpp Widget::Widget(QWidget *parent) : QWidget(parent) { te = new Teacher(this ); st = new Student(this ); void (Teacher::*teacherSignal)(QString) = &Teacher::hungry; void (Student::*studentSlot)(QString) = &Student::treat; connect (te, teacherSignal, st, studentSlot); QPushButton *btn = new QPushButton("下课" , this ); resize(600 , 400 ); connect (btn, &QPushButton::clicked, this , &Widget::ClassOver); void (Teacher::*teacherSignal2)() = &Teacher::hungry; void (Student::*studentSlot2)() = &Student::treat; connect (te, teacherSignal2, st, studentSlot2); connect (btn, &QPushButton::clicked, te, teacherSignal2); disconnect (te, teacherSignal2, st, studentSlot2); } void Widget::ClassOver () { emit te->hungry("宫保鸡丁" ); }
信号也可以直接连接信号。
可以使用disconnect()
断开信号。
注意点:
一个信号可以连接多个槽函数。
多个信号可以连接同一个槽函数。
信号与槽函数的参数类型必须一一对应
信号的参数数量可以多于槽函数的参数数量(但匹配的部分参数类型必须一一对应)
信号槽经常和Lambda表达式结合使用。
Qt4及以前版本的信号槽连接 1 2 connect (te, SIGNAL(hungry()), st, SLOT(treat()));connect (te, SIGNAL(hungry(QString)), st, SLOT(treat(QString)));
优点:参数直观
缺点:编译时类型不做检测