QT中类对象之间的通信尽量少使用信号槽

·  阅读 656

大家都知道在QT中的信号槽是一种非常重要的方法,这种方法可以使不同的类对象之间进行高效的通信,而且这也是QT区别于其他框架的重要机制之一。这就像MFC和WIN32的消息机制一样。

但是我希望大家以后在使用QT时还是尽量少使用信号槽实现是对象之间的通信。除了一些必须的场合,比如按钮的点击事件、列表框的切换事件等。

为什么这样说呢?

一、在结构上来说,连接信号槽的地方、发射信号的地方、接受信号的地方往往不在一个地方或者离得很近的地方,有时不在一个模块中,这就给代码的阅读带来的很大的困难。当读到发射信号的地方,需要知道这个信号是发给谁的,同理阅读到槽函数时,也需要知道是哪个类对象发射出的哪个信号。当查看完信号槽连接的地方,弄明白发射和接受对象之后,继续在原来的地方阅读代码,往往会打断之前的思路,还有重新花时间来整理思路。就像线程之间的来回切换一下,每次切换都是需要资源成本的。

二、信号槽机制有点像C/C++中的goto句。第一次学C语言的时候,老师就说过,不要使用goto语句,会破坏代码的模块化,但是不明白为什么。随着经验的增加,发现模块与模块之间的高内聚和低耦合是多么的重要!而信号槽这种设计又非常的灵活,可以在不通过类、不用的模块之间发射和接受信号,这也就大大的破坏了模块之间的高内聚性。当开发的模块增多,开发的人员增加后,这种问题就会更加的凸显出来。

那么在QT中如果不使用信号槽在对象之间进行通信,该使用什么方法在不同的类对象之间进行通信呢?

下面看一个例子,先使用信号槽进行通信。 介绍:有两个界面:第一个界面和第二个界面,第一个界面有一个Label,第二个界面有一个编辑框。当点击第一个界面的按钮的时候,弹出第二个界面,当在第二个界面的编辑框编辑完成之后,点击按钮,编辑的内容就会在第一个界面的Label上显示出来。 在这里插入图片描述 代码如下: 第一个界面:

#pragma once

#include <QtWidgets/QMainWindow>
#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 <QWidget>
#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 <QString>

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 <QtWidgets/QMainWindow>
#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 <QWidget>
#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

分类:
后端
标签: