Qt同一信号与槽重复连接问题

  1. 1. Qt同一信号与槽函数重复连接

Qt同一信号与槽函数重复连接

都知道在QT中一个信号可以与多个槽函数连接,一个槽函数也可以与多个信号连接。那么,如果一个信号与一个槽函数多次连接然后发送信号会发生什么呢?编译失败?运行时出现异常?只运行一次槽函数还是会多次运行呢?

看以下代码:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//h
class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();

public slots:
void on_pushButton_clicked();
void signSlot();

public:
signals:
void sign();

private:
Ui::MainWindow *ui;
uint8_t flag{0};
};

//cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::signSlot()
{
this->flag++;
qDebug() << this->flag;
}

void MainWindow::on_pushButton_clicked()
{
emit sign();
}

该ui有一个按钮,点击此按钮会发送一个信号,而这个信号与一个槽函数重复连接了三次,运行一下看结果:

1
2
3
1
2
3

可以看到槽函数被运行了三次。***也就是说,如果一个信号与一个槽函数多次连接(假设是n次)的话,在发送信号后,一般槽函数就会被调用多少次(n)***。

如果此时取消信号槽的连接会怎么样呢?

1
2
3
4
connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
disconnect(this, &MainWindow::sign, this, &MainWindow::signSlot);

再点击按钮,什么都不会输出,槽函数未被调用。所以调用disconnect会把在调用之前指定的信号与槽的连接全部取消掉,而不是只取消一次(就和没有连接过一样)。之后在连接的话,现象依旧。

除了通过disconnect防止这种情况的发生之外,也可以通过指定连接方式避免:

1
2
3
4
5
6
7
8
9
    qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot, Qt::UniqueConnection);
qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot, Qt::UniqueConnection);
qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot, Qt::UniqueConnection);
/**
true
false
false
1
*/

此时,只有第一个是连接成功的,所以只执行了一次。再看下面:

1
2
3
4
5
6
7
8
9
10
    qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot, Qt::UniqueConnection);
qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
/**
true
false
true
1
2
*/

可以看到第一,三次全部连接成功。

再试几种情况:

1
2
3
4
5
6
7
8
9
    qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot, Qt::UniqueConnection);    
qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
/**
true
true
true
*/

1
2
3
4
5
6
7
8
    qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot);
qDebug() << connect(this, &MainWindow::sign, this, &MainWindow::signSlot, Qt::UniqueConnection);
/**
true
true
false
*/

个人看法,可以把Qt::UniqueConnection理解成一个标志位,在连接信号槽时,如果加了这个标志位,那么QT会检查这对信号槽有没有连接过,连接过,不会去再次连接,没有连接过才会去连接。而不加这个标志位,QT是不会去检查是否连接过的,会直接进行连接