以下是本人学习笔记
原视频:最新QT从入门到实战完整版|传智教育
初学者基类可以选择QWidget,QWidget是QMainWindow和QDialog的基类
讲解见代码注释
main.cpp
#include "mywidget.h"
#include // 包含一个应用程序类的头文件
int main(int argc, char *argv[])
{
// a:应用程序对象,Qt中,有且仅有一个应用程序对象
QApplication a(argc, argv);
// 窗口对象,mywidget父类:QWidget
myWidget w;
// 窗口对象默认不会显示,必须调用show方法显示窗口
w.show();
// 让应用程序对象进入消息循环机制(对象一直在捕获消息)
// 使代码阻塞在该行
return a.exec();
}
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include // 包含头文件QWidget窗口类
class myWidget : public QWidget
{
Q_OBJECT // Q_OBJECT宏,允许类中使用信号和槽的机制
public:
// 构造函数(parent默认值为0,默认值的设定在声明和构造中只能有一处有)
myWidget(QWidget *parent = 0);
~myWidget();
};
#endif // MYWIDGET_H
mywidget.cpp
#include "mywidget.h"
#include
myWidget::myWidget(QWidget *parent)
: QWidget(parent)
{
// 创建一个按钮
QPushButton* btn1 = new QPushButton;
btn1->setParent(this);
btn1->setText("hello");
// 创建按钮2:更快捷,但是有弊端:会按照控件的大小创建窗口
QPushButton* btn2 = new QPushButton("hello again", this);
// 移动按钮2
btn2->move(100, 100);
// 所以可以reset窗口大小
resize(600, 400);
// 设置固定窗口大小
setFixedSize(600, 400);
// 设置窗口标题
setWindowTitle("this is a window");
}
myWidget::~myWidget()
{
}
在Qt中创建对象会提供一个Parent对象指针
例:创建一个新类
MyPushButton.h
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H
#include
class MyPushButton : public QPushButton
{
Q_OBJECT
public:
explicit MyPushButton(QPushButton *parent = 0);
~MyPushButton();
signals:
public slots:
};
#endif // MYPUSHBUTTON_H
MyPushButton.cpp
#include "mypushbutton.h"
#include
MyPushButton::MyPushButton(QPushButton *parent) : QPushButton(parent)
{
qDebug() << "call button class";
}
MyPushButton::~MyPushButton()
{
qDebug() << "~MyPushButton";
}
connect(信号的发送者, 发送的具体信号, 信号的接收者, 信号的处理(槽))
信号槽的优点:松散耦合,信号发送端和信号接收端本身是没有关联的,通过connect函数连接,将两端耦合在一起
mywidget.cpp
#include "mywidget.h"
#include
#include "mypushbutton.h"
myWidget::myWidget(QWidget *parent)
: QWidget(parent)
{
// 创建一个按钮
QPushButton* btn1 = new QPushButton;
btn1->setParent(this);
btn1->setText("hello");
// 创建按钮2:更快捷,但是有弊端:会按照控件的大小创建窗口
QPushButton* btn2 = new QPushButton("hello again", this);
// 移动按钮2
btn2->move(100, 100);
btn2->resize(100, 100);
// 创建按钮3
MyPushButton* btn3 = new MyPushButton;
btn3->setText("hello a and a");
btn3->setParent(this);
btn3->move(200,200);
// 所以可以reset窗口大小
resize(600, 400);
// 设置固定窗口大小
setFixedSize(600, 400);
// 设置窗口标题
setWindowTitle("this is a window");
// 需求:点击按钮,关闭窗口
connect(btn1, &MyPushButton::clicked, this, &myWidget::close);
}
myWidget::~myWidget()
{
}
Student类
#ifndef STUDENT_H
#define STUDENT_H
#include
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
signals:
public slots:
// 早期Qt版本,槽函数必须写到public slots,高级版本可以写到public或者全局下
// 返回值void,需要声明,也需要实现
// 可以有参数,可以发生重载
void treat();
};
#endif // STUDENT_H
#include "student.h"
#include
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::treat()
{
qDebug() << "treat teacher";
}
Teacher类
#ifndef TEACHER_H
#define TEACHER_H
#include
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
// 自定义信号写到signals下
// 返回值是void,只需要声明,不需要实现
// 可以有参数,可以重载
void hungry();
public slots:
};
#endif // TEACHER_H
#include "teacher.h"
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
MyWidget
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include
#include "teacher.h"
#include "student.h"
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
private:
Ui::MyWidget *ui;
Teacher* sir;
Student* son;
void classOver();
};
#endif // MYWIDGET_H
#include "mywidget.h"
#include "ui_mywidget.h"
// 模拟场景
// Teacher类 Student类
// 下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this);
// 创建一个老师对象
this->sir = new Teacher(this);
// 创建一个学生对象
this->son = new Student(this);
// connect
connect(sir, &Teacher::hungry, son, &Student::treat);
// 调用下课函数
classOver();
}
void MyWidget::classOver()
{
// 下课函数,触发老师饿了的信号
emit sir->hungry();
}
MyWidget::~MyWidget()
{
delete ui;
}
注意连接和触发信号的顺序!
触发自定义信号:emit 自定义信号
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
// 模拟场景
// Teacher类 Student类
// 下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this);
// 创建一个老师对象
this->sir = new Teacher(this);
// 创建一个学生对象
this->son = new Student(this);
// connect
// connect(sir, &Teacher::hungry, son, &Student::treat);
// 指针指向地址
// 函数指针指向函数地址
void(Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
void(Student:: *studentSlot)(QString) = &Student::treat;
// 连接带参数的信号和槽
connect(sir, teacherSignal, son, studentSlot);
// 调用下课函数
classOver();
}
void MyWidget::classOver()
{
// 下课函数,触发老师饿了的信号
// emit sir->hungry();
emit sir->hungry("cola");
}
MyWidget::~MyWidget()
{
delete ui;
}
如果函数有重载,在连接信号槽时就需要创建函数指针,寻找到指定函数,明确指向函数地址
按钮点击信号->老师信号->学生请客
详见注释
mywidget.cpp
#include "mywidget.h"
#include "ui_mywidget.h"
#include
// 模拟场景
// Teacher类 Student类
// 下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyWidget)
{
ui->setupUi(this);
// 创建一个老师对象
this->sir = new Teacher(this);
// 创建一个学生对象
this->son = new Student(this);
// 指针指向地址
// 函数指针指向函数地址:带参数的信号和槽
void(Teacher:: *teacherSignal1)(QString) = &Teacher::hungry;
void(Student:: *studentSlot1)(QString) = &Student::treat;
// no带参数的信号和槽
void(Teacher:: *teacherSignal2)(void) = &Teacher::hungry;
void(Student:: *studentSlot2)(void) = &Student::treat;
// 连接带参数的信号和槽
connect(sir, teacherSignal1, son, studentSlot1);
// 连接no参数的信号和槽
connect(sir, teacherSignal2, son, studentSlot2);
// press button -> class over
QPushButton* btn1 = new QPushButton("class over 1", this);
QPushButton* btn2 = new QPushButton("class over 2", this);
btn2->move(100, 0);
this->resize(600, 400);
// 信号连接槽
connect(btn1, &QPushButton::clicked, this, &MyWidget::classOver);
// 信号连接信号
connect(btn2, &QPushButton::clicked, sir, teacherSignal2);
// 断开信号
// disconnect(sir, teacherSignal1, son, studentSlot1);
disconnect(sir, teacherSignal2, son, studentSlot2);
}
void MyWidget::classOver()
{
// 下课函数,触发老师饿了的信号
emit sir->hungry();
emit sir->hungry("cola");
}
MyWidget::~MyWidget()
{
delete ui;
}
qt版本5.4及之前需要在.pro文件中添加CONFIG += c++11才可以使用Lambda表达式(在文件末尾添加即可)
c++11中的Lambda表达式用于定义并创建匿名的函数对象
一个基础的Lambda表达式结构:
[](){}
函数声明
[=](){
btn->setText("btnn");
}
函数声明及调用
[=](){
btn->setText("btnn");
}()
解释:
空: 没有使用任何函数对象参数
=: 函数体内可以使用上述范围中的所有参数,值传递
&: 函数体内可以使用上述范围中的所有参数,引用传递
this: 可以使用Lambda所在类中的成员变量
a: 只能使用a的值,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符(但是无法修改参数本身)
&a: a引用传递
=,&a: 除了a引用传递,其余值传递
&,a: 除了a值传递,其余引用传递
int ret = []()->int{return 1000;}();
例:使用Lambda表达式 实现点击按钮 关闭窗口
// 信号连接信号(带参数)
connect(btn2, &QPushButton::clicked, sir, [=](){
emit sir->hungry("cola");
btn2->resize(120, 50);
});
使用lambda的好处:连接时,无参的信号不可以连接有参的槽函数/信号,使用Lambda表达式可以在函数体中触发有参信号
设计一个按钮,点击时弹出新窗口,再次点击时新窗口关闭