那些难过的日子,都一起陪伴,也不说些什么大道理。
难过的时候,所有人都给你讲一堆大道理。
只有你的好朋友,懂你的沉默,陪你一起在墙角蹲着。
对象树
QT中创建QObject对象会时,构造函数会接收一个Parent父对象指针作为参数。
这就于相当于创建QObject对象时,可以提供一个父类,创建的QObject对象会自动添加到父对象的children()列表中。
当父对象析构时,这个列表中的所有对象都会被析构。例:一个按钮有一个QShortcut(快捷键)作为子对象,删除按钮类时,快捷键也被删除。
这种机制被称为对象树,QObject是以对象树的形式组织起来的,从QObject类向下(子对象)构造,析构时自下(子对象)往上(父对象)析构。
当创建的对象在在堆区时(指定父对象为QObject子类或者其派生类---setParent()),可以不用管理释放操作,一定程度上简化了内存回收机制。
信号和槽
connect(信号发送者,发送具体的信号(信号函数的地址),信号接收者,信号处理函数(槽函数的地址))
信号槽的优点,松散耦合,接收与发送之间没有关联,通过connect连接。
mainwindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>//包含头文件MainWindow窗口类
class MainWindow : public QMainWindow
{
Q_OBJECT//Q_OBJECT类,允许使用信号和槽机制
public:
MainWindow(QWidget *parent = nullptr);//Mainwindow的有参构造函数,参数默认值为0,空指针,在声明和构造中只有一个有参数的默认值
~MainWindow();
};
#endif // MAINWINDOW_H
mypushbutton.h文件
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H
#include <QPushButton>
class MyPushButton : public QPushButton
{
Q_OBJECT
public:
explicit MyPushButton(QWidget *parent = nullptr);//系统提供的析构函数
~MyPushButton();
signals:
};
#endif // MYPUSHBUTTON_H
main.cpp文件
#include "mainwindow.h"
#include <QApplication>//包含一个应用程序的头文件
int main(int argc, char *argv[])//argc 命令行变量的数量,argv命令行变量的数组
{
QApplication a(argc, argv);//应用程序的对象,有且只有一个
MainWindow w;//主窗口程序对象
w.show();//窗口对象不会默认显示,需要调用Show方法显示窗口
return a.exec();//让应用对象进入消息循环,代码会阻塞的这一行,不会执行接下来的代码
}
MainWindow.cpp文件
#include "mainwindow.h"
#include <QPushButton>//按钮类头文件
#include "mypushbutton.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)//初始化列表
{
resize(200,200);//重置窗口大小
setWindowTitle("第一个窗口");//设置主窗口标题
setFixedSize(200,200);//设置窗口为固定大小
QPushButton *btn =new QPushButton;
btn->setParent(this);//让创建的按钮依赖于MainWindow窗口
btn->resize(100,25);//重置按钮大小
btn->setText("第一个按钮");//显示文本
//创建第二个按钮,按照控件大小创建窗口
QPushButton *btn2=new QPushButton("第二个按钮",this);
btn2->move(50,50);//移动btn2按钮
btn->move(50,0);
//创建自定义按钮
MyPushButton *mbtn=new MyPushButton;
mbtn->setText("我的按钮");
mbtn->setParent(this);
mbtn->resize(100,25);
mbtn->move(50,100);
//两种书写方式,由于信号是继承父类的,信号与槽可以用父类的函数地址,也可以使用自己的函数地址
connect(btn,&QPushButton::clicked,this,&QWidget::close);//点击“第一个按钮”,关闭窗口
connect(mbtn,&MyPushButton::clicked,this,&MainWindow::close);
qDebug()<<"调用MainWIndow构造函数";//打印顺序相反,原因是程序运行到这一行,会先确认该类是否存在子类,如果有会暂停析构,跳转到子类的析构函数,执行子类的析构,子类析构完继续析构该类
}
MainWindow::~MainWindow() {
qDebug()<<"调用MainWIndow析构函数";
}
mypushbutton.cpp文件
#include "mypushbutton.h"
#include <QDebug>//打印调试信息
MyPushButton::MyPushButton(QWidget *parent)
: QPushButton{parent}
{
qDebug()<<"调用我的按钮构造函数";
}
MyPushButton::~MyPushButton()
{
qDebug()<<"调用我的按钮析构函数";
}
拓展:
1.信号可以与连接信号
2.信号可以连接多个槽函数
3.多个信号可以连接一个槽函数
4.槽函数跟信号的参数类型必须一一对应,参数个数可以不一致,信号的参数个数可以多于槽函数的参数个数。
需求:使用QPushButton类实现下课了,老师布置作业,学生写作业
mainwindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include "student.h"
#include "teacher.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void classOver();
private:
Ui::MainWindow *ui;
Student *st;
Teacher *te;
};
#endif // MAINWINDOW_H
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 writeHW();//早期Qt版本槽函数必须写道public slots下,高级版本可以写到public或者全局下。
void writeHW(QString homework);//槽函数重载
};
#endif // STUDENT_H
teacher.h文件
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
void assignHW();//信号需要声明,不需要实现(重点),有参数可以重载。需要声明不需要实现,可以有参数可以重载
void assignHW(QString string);//信号重载
public slots:
};
#endif // TEACHER_H
main.cpp文件
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp文件
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QPushButton>
#include <QDebug>
//放学了,老师布置作业,学生写作业
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
st=new Student(this);//指定父对象为MainWindow
te=new Teacher(this);
// resize(200,200);
// QPushButton *btn=new QPushButton("按钮一",this);
// btn->resize(80,30);
// btn->move(60,85);
//connect(te,Teacher::assignHW,st,Student::writeHW)
// void (Teacher::*TeHomeworkS)(QString)=&Teacher::assignHW;重载后使用上述方式,编译器无法识别函数出来的版本和重载版本使用函数指针指向函数地址
// void (Student::*StHomeworkW)(QString)=&Student::writeHW;
// connect(te,TeHomeworkS,st,StHomeworkW);//连接带参数的信号与槽
// classOver();
// void (Teacher::*TeHomeworkS1)(void)=&Teacher::assignHW;//无参信号函数指针
// void (Student::*StHomeworkW1)(void)=&Student::writeHW;
// connect(te,TeHomeworkS1,st,StHomeworkW1);
// connect(btn,&QPushButton::clicked,te,TeHomeworkS1); //信号与信号连接
// disconnect(btn,&QPushButton::clicked,te,TeHomeworkS1);//断开连接
//
// connect(te,SIGNAL(assignHW()),st,SLOT(writeHW()));//QT4以前的信号和槽的连接方式,参数直观,但是不做类型检测, connect(te,SIGNAL(assignHW()),st,SLOT(writeHW(QString)));编译器不报错
// connect(btn,SIGNAL(clicked()),te,SIGNAL(assignHW()));//底层逻辑是将函数名转换为字符串去匹配函数
QPushButton *btn4=new QPushButton("吃饭",this);
connect(btn4,&QPushButton::clicked,[=](){
emit st->writeHW("数学");
});//使用lambda表达式实现连接,第三个参数是this,可以省略。可以在表达式内调用任何想调用的函数
// [=](){
// btn->setText("aaa");
// }();//最后这个小括号是使函数函数声明改编为函数调用,表达式内部调用了函数
//Lambda表达式[](){}分别为标识符(匿名函数)、参数、实现体,=可以使用表达式所在的作用范围内所有的局部变量,通过值传递的形式,推荐值传递;&是引用传递
//表达式返回值,[]()->int{return int类型的值;}();
// QPushButton *btn2=new QPushButton(this);
// QPushButton *btn3=new QPushButton(this);
// btn3->move(100,100);
// int m=10;
// connect(btn2,&QPushButton::clicked,this,[m]()mutable{m=100+10;qDebug()<<m;});//[]()mutable{},mutable关键字用于修饰值传递的变量,修改的是拷贝不是本体
// connect(btn3,&QPushButton::clicked,this,[=](){qDebug()<<m;});
// qDebug()<<m;
}
void MainWindow::classOver()
{
emit te->assignHW("语文");
}
MainWindow::~MainWindow()
{
delete ui;
}
student.cpp
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent)
: QObject{parent}
{
}
void Student::writeHW()
{
qDebug()<<"学生写作业";
}
void Student::writeHW(QString homework)
{
//QString 转换为char * 先转成QByteArray(.toUtf8()),再转换为char*(.data()))
qDebug()<<"学生写"<<homework.toUtf8().data()<<"作业";
}
teacher.cpp文件
#include "teacher.h"
#include <QDebug>
Teacher::Teacher(QObject *parent)
: QObject{parent}
{
}
C++之前的早期版本使用Lambda表达式需要在project文件中添加
CONDIG +=C++11