大家都知道在QT中的信号槽是一种非常重要的方法,这种方法可以使不同的类对象之间进行高效的通信,而且这也是QT区别于其他框架的重要机制之一。这就像MFC和WIN32的消息机制一样。
但是我希望大家以后在使用QT时还是尽量少使用信号槽实现是对象之间的通信。除了一些必须的场合,比如按钮的点击事件、列表框的切换事件等。
为什么这样说呢?
一、在结构上来说,连接信号槽的地方、发射信号的地方、接受信号的地方往往不在一个地方或者离得很近的地方,有时不在一个模块中,这就给代码的阅读带来的很大的困难。当读到发射信号的地方,需要知道这个信号是发给谁的,同理阅读到槽函数时,也需要知道是哪个类对象发射出的哪个信号。当查看完信号槽连接的地方,弄明白发射和接受对象之后,继续在原来的地方阅读代码,往往会打断之前的思路,还有重新花时间来整理思路。就像线程之间的来回切换一下,每次切换都是需要资源成本的。
二、信号槽机制有点像C/C++中的goto句。第一次学C语言的时候,老师就说过,不要使用goto语句,会破坏代码的模块化,但是不明白为什么。随着经验的增加,发现模块与模块之间的高内聚和低耦合是多么的重要!而信号槽这种设计又非常的灵活,可以在不通过类、不用的模块之间发射和接受信号,这也就大大的破坏了模块之间的高内聚性。当开发的模块增多,开发的人员增加后,这种问题就会更加的凸显出来。
那么在QT中如果不使用信号槽在对象之间进行通信,该使用什么方法在不同的类对象之间进行通信呢?
下面看一个例子,先使用信号槽进行通信。
介绍:有两个界面:第一个界面和第二个界面,第一个界面有一个Label,第二个界面有一个编辑框。当点击第一个界面的按钮的时候,弹出第二个界面,当在第二个界面的编辑框编辑完成之后,点击按钮,编辑的内容就会在第一个界面的Label上显示出来。
代码如下:
第一个界面:
#pragma once
#include
#include "ui_SignalSlot.h"
class QtGuiSecond;
class SignalSlot : public QMainWindow {
Q_OBJECT
public:
SignalSlot(QWidget *parent = Q_NULLPTR);
private:
void init();
private slots:
void slotBtn();
void slotEditStr(QString str);
private:
Ui::SignalSlotClass ui;
QtGuiSecond* _guiSecond = nullptr;
};
#include "SignalSlot.h"
#include "QtGuiSecond.h"
SignalSlot::SignalSlot(QWidget *parent)
: QMainWindow(parent) {
ui.setupUi(this);
init();
}
void SignalSlot::init() {
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(slotBtn()));
_guiSecond = new QtGuiSecond;
connect(_guiSecond, SIGNAL(sigEditStr(QString)), this, SLOT(slotEditStr(QString)));
}
void SignalSlot::slotBtn() {
_guiSecond->show();
}
void SignalSlot::slotEditStr(QString str) {
ui.label->setText(str);
}
第二个界面:
#pragma once
#include
#include "ui_QtGuiSecond.h"
class QtGuiSecond : public QWidget {
Q_OBJECT
public:
QtGuiSecond(QWidget *parent = Q_NULLPTR);
~QtGuiSecond();
private:
void init();
private slots:
void slotOK();
signals:
void sigEditStr(QString);
private:
Ui::QtGuiSecond ui;
};
#include "QtGuiSecond.h"
QtGuiSecond::QtGuiSecond(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this);
init();
}
QtGuiSecond::~QtGuiSecond() {
}
void QtGuiSecond::init() {
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(slotOK()));
}
void QtGuiSecond::slotOK() {
QString str = ui.lineEdit->text();
emit sigEditStr(str);
}
可以看到第二个界面编辑的内容是通过信号槽的方式传过去了。
如果不使用信号槽该怎么传递数据呢?
这就需要我们添加第三个类,也就是接口类,这个类的目的就是为了传递参数的。
#pragma once
#include
class IEditArg {
public:
IEditArg();
~IEditArg();
virtual void editStr(QString str);
};
#include "IEditArg.h"
IEditArg::IEditArg() {
}
IEditArg::~IEditArg() {
}
void IEditArg::editStr(QString str) {
}
然后让第一个界面类继承这个类,并且实现里面的虚函数:
#pragma once
#include
#include "ui_SignalSlot.h"
#include "IEditArg.h"
class QtGuiSecond;
class SignalSlot : public QMainWindow, public IEditArg {
Q_OBJECT
public:
SignalSlot(QWidget *parent = Q_NULLPTR);
void editStr(QString str)override;
private:
void init();
private slots:
void slotBtn();
private:
Ui::SignalSlotClass ui;
QtGuiSecond* _guiSecond = nullptr;
};
#include "SignalSlot.h"
#include "QtGuiSecond.h"
SignalSlot::SignalSlot(QWidget *parent)
: QMainWindow(parent) {
ui.setupUi(this);
init();
}
void SignalSlot::editStr(QString str) {
ui.label->setText(str);
}
void SignalSlot::init() {
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(slotBtn()));
_guiSecond = new QtGuiSecond;
_guiSecond->setArgInterface(this);
}
void SignalSlot::slotBtn() {
_guiSecond->show();
}
第二个界面类保存这个接口:
#pragma once
#include
#include "ui_QtGuiSecond.h"
class IEditArg;
class QtGuiSecond : public QWidget {
Q_OBJECT
public:
QtGuiSecond(QWidget *parent = Q_NULLPTR);
~QtGuiSecond();
void setArgInterface(IEditArg* editArg);
private:
void init();
private slots:
void slotOK();
private:
Ui::QtGuiSecond ui;
IEditArg* _editArg = nullptr;
};
#include "QtGuiSecond.h"
#include "IEditArg.h"
QtGuiSecond::QtGuiSecond(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this);
init();
}
QtGuiSecond::~QtGuiSecond() {
}
void QtGuiSecond::setArgInterface(IEditArg* editArg) {
_editArg = editArg;
}
void QtGuiSecond::init() {
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(slotOK()));
}
void QtGuiSecond::slotOK() {
QString str = ui.lineEdit->text();
if (_editArg!=nullptr){
_editArg->editStr(str);
}
}
这样就完成了,虽然代码多了一些但是结构更清晰了!同样也是实现相同的功能呢!有利用了C++的特性。
aaa