单例模式与信号中心3

信号中心的实现及其注意事项。

信号中心

信号中心用来转发单例模式与信号中心1-开头问题中的信号,可大大减少信号的传递次数和函数调用的层数,其实现方式如下所示:

signalcenter.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <QObject>

class SignalCenter : public QObject
{
Q_OBJECT
public:
SignalCenter(const SignalCenter&) = delete;
SignalCenter(SignalCenter&&) = delete;

SignalCenter& operator=(const SignalCenter&) = delete;
SignalCenter& operator=(SignalCenter&&) = delete;
static SignalCenter& getInstance()
{
static SignalCenter instance;
return instance;
}

private:
SignalCenter() = default;

signals:
void senderButtonClicked();
};
  1. 该类需继承自QObject;
  2. 使用Q_OBJECT宏并定义相关信号。

senderframe.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "senderframe.h"
#include <QHBoxLayout>
#include "signalcenter.h"

SenderFrame::SenderFrame(QWidget *parent) :
QFrame(parent)
{
init();
}

SenderFrame::~SenderFrame()
{

}

void SenderFrame::init()
{
button_ = new QPushButton(u8"发送",this);

QHBoxLayout* hLayout = new QHBoxLayout;
hLayout->addWidget(button_);

this->setLayout(hLayout);
this->setStyleSheet("background:blue;");

//为了演示简单,将connect写在了类里面,这样会导致该类所有的实例都会connect
connect(button_, &QPushButton::clicked,
&SignalCenter::getInstance(), &SignalCenter::senderButtonClicked);
}

receiverframe.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "receiverframe.h"
#include <QHBoxLayout>
#include "signalcenter.h"

ReceiverFrame::ReceiverFrame(QWidget *parent) :
QFrame(parent)
{
init();
}

ReceiverFrame::~ReceiverFrame()
{

}

void ReceiverFrame::init()
{
label_ = new QLabel(this);

QHBoxLayout* hLayout = new QHBoxLayout;
hLayout->addWidget(label_);

this->setLayout(hLayout);
this->setStyleSheet("background:green;");

//为了演示简单,将connect写在在类里面,这样会导致该类所有的实例都会connect
connect(&SignalCenter::getInstance(), &SignalCenter::senderButtonClicked, [=]() {
static int i = 0;

label_->setText(QString(u8"第%1次点击").arg(++i));
});
}
  1. senderframe.cppreceiverframe.cpp中各自与SignalCenter单例类connect,借助于SignalCenter单例类完成了信号的转发;
  2. 如注释所言,为了演示简单,该例将connect写在了类里面,这样会导致该类所有的实例都会connect,比如ReceiverFrame类公用,被实例化了两个实例,这样会导致点击一次按钮,两个实例都改变文字。所以将与SignalCenter单例类的connect,放到其父控件中更合适。

mainwindow.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "mainwindow.h"
#include "receiverframe.h"
#include "senderframe.h"
#include <QHBoxLayout>
#include <QDateTime>

MainWindow::MainWindow(QWidget *parent)
: QDialog(parent)
{
init();
}

MainWindow::~MainWindow()
{

}

void MainWindow::init()
{
auto senderFrame = new SenderFrame(this);
auto receiverFrame = new ReceiverFrame(this);

QHBoxLayout* hLayout = new QHBoxLayout;
hLayout->setContentsMargins(0, 0, 0, 0);
hLayout->setSpacing(20);

hLayout->addWidget(senderFrame);
hLayout->addWidget(receiverFrame);

this->setLayout(hLayout);
this->setStyleSheet("background:yellow;");
this->setFixedSize(600, 400);
}

可以看出,在mainwindow.cpp中只是实例化了SenderFrameReceiverFrame类,并没有connect二者,但是信号正常的由SenderFrame发送到了ReceiverFrame类。运行结果如下: