使用mainwindow构建
Signal
在Qt中,信号(signals)是特殊的成员函数,它们用于对象间的通信,并且有一些特殊的规则:
-
没有返回值:信号的实现(即函数体)通常是不需要的,也是不允许的。信号的实现由Qt的元对象系统(通过MOC)自动处理。
-
不能有函数体:在Qt中,信号通常没有函数体。它们被声明为没有实现的函数原型,MOC工具会处理这些声明并生成必要的代码来连接信号和槽。
-
使用
Q_OBJECT
宏:包含信号的类必须继承自QObject
(或其子类),并且必须在类的私有部分包含Q_OBJECT
宏。这个宏为类启用了Qt的元对象系统,包括信号和槽的机制。 -
槽函数的参数列表必须和信号函数的参数列表一致,如果不一致,槽函数的参数列表必须比信号函数的参数列表少。
-
信号与槽的连接可以一对多,也可以多对一
以下是一个简单的emit发射信号示例代码
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<QPushButton>
#include<QApplication>
#include<QMessageBox>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "wanted.h"
#include "foods.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
Foods *foods1;
Wanted *wanted1;
void emitSingal();//声明发射信号函数
};
#endif // MAINWINDOW_H
//mainwindoww.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
foods1 = new Foods(this);
wanted1 = new Wanted();
QObject::connect(wanted1, &Wanted::signalOne, foods1, &Foods::slotOne);//连接信号和槽函数
emitSingal();//使用函数发射信号
}
void MainWindow::emitSingal(){
emit wanted1->signalOne();
}//发射信号函数的具体实现
MainWindow::~MainWindow()
{
delete ui;
}
//wanted.h
#ifndef WANTED_H
#define WANTED_H
#include <QMainWindow>
#include <QObject>
#include <QWidget>
class Wanted:public QObject
{
Q_OBJECT
public:
Wanted(QMainWindow *parent = nullptr);
~Wanted();
signals:
void signalOne();//声明了信号一
};
#endif // WANTED_H
//wanted.cpp
#include "wanted.h"
Wanted::Wanted(QMainWindow *parent) {
}//无需具体实现信号函数
Wanted::~Wanted()
{
}
//foods.h
#ifndef FOODS_H
#define FOODS_H
#include <QMainWindow>
#include <QObject>
#include <QWidget>
class Foods:public QObject
{
Q_OBJECT
public:
Foods(QMainWindow *parent = nullptr);
~Foods();
void slotOne();//定义了slotOne槽函数,在某些低版本Qt中,需要先声明public slots:
};
#endif // FOODS_H
//foods.cpp
#include "foods.h"
Foods::Foods(QMainWindow *parent) {
}//QMainWindow作为父类,而不是QWidget
Foods::~Foods()
{}
void Foods::slotOne(){
qDebug("foods");
}//槽函数的具体实现
输出结果
重载函数的情况
当信号和槽有重载函数时,可以使用函数指针或者宏的方法调用具体的重载函数
//wanted.h
signals:
void signalOne();
void signalOne(QString a);//新增了一个重载函数
//foods.h
void slotOne();
void slotOne(QString a);//槽函数与信号函数同步,也声明一个返回值相同,形参相同的重载函数
//foods.cpp
void Foods::slotOne(){
qDebug("foods");
}
void Foods::slotOne(QString a){
qDebug()<< a;
}//槽重载函数的具体实现
//mainwindow.cpp
//
foods1 = new Foods(this);
wanted1 = new Wanted();
void(Wanted:: *wanten1Signal)(QString)=&Wanted::signalOne;
void(Foods:: *foodsSignal)(QString)=&Foods::slotOne;//当信号函数和槽函数有了重载函数以后,可以创建函数指针明确指向的是哪一个函数,否则原先的QObject::connect(wanted1, &Wanted::signalOne, foods1, &Foods::slotOne);编译会不通过
QObject::connect(wanted1, wanten1Signal, foods1, foodsSignal);
//QObject::connect(wanted1, SIGNAL(signalOne(QString)), foods1, SLOT(slotOne(QString)));这一行代码效果和上一行一样,只不过上一行使用了指针,不过这一行使用SIGNAL和SLOT宏来具体指定连接哪一个重载函数,无需创建指针
emitSingal();
}
void MainWindow::emitSingal(){
emit wanted1->signalOne("coffee");
}
输出结果:
可以看到这里输出的不是字符串原本的内容,而是在原有的基础上加上了双引号
要解决这个问题,把qDebug()<< a改为qDebug()<< a.toUtf8().data(),既先把a转换成QByteArray再转换成char *
断开连接
假设连接这么写:QObject::connect(wanted1, &Wanted::signalOne, foods1, &Foods::slotOne);
那么断开连接把connect改为disconnect就行了QObject::disconnect(wanted1, &Wanted::signalOne, foods1, &Foods::slotOne);
或者在连接的同时用一个对象接收连接的情况再断开:QMetaObject::Connection res =QObject::connect(wanted1, &Wanted::signalOne, foods1, &Foods::slotOne);
QObject::disconnect(res);
断开signalOne与其响应的所有槽的连接:QObject::disconnect(wanted1, &Wanted::signalOne, 0,0);
断开this信号和this的所有槽的连接QObject::disconnect(this, 0, this,0);