调用时更改插槽中的信号插槽连接

时间:2012-12-02 19:25:20

标签: qt signals-slots

当用户操作在每个运行时初始化应用程序数据时,我有一个用例。为了表示这种行为,我的示例代码为:

SignalSlotChange.h

#ifndef SIGNALSLOTCHANGE_H
#define SIGNALSLOTCHANGE_H

#include <QtGui>

class SignalSlotChange : public QWidget
{
Q_OBJECT

public:
    SignalSlotChange(QWidget *parent = 0);

private slots:
    void firstCall();
    void secondCall();

private:
    QPushButton *button;

};

#endif // SIGNALSLOTCHANGE_H

SignalSlotChange.cpp

#include "SignalSlotChange.h"

SignalSlotChange::SignalSlotChange(QWidget *parent) : QWidget(parent)
{
    button = new QPushButton("Messgage", this);
    QObject::connect(button, SIGNAL(clicked()), this, SLOT(firstCall()));
    show();
}

void SignalSlotChange::firstCall()
{
    QMessageBox::information(this, "SignalSlotChange", "First call", QMessageBox::Ok, QMessageBox::NoButton);
    // Change the signal-slot connection to secondCall()
    QObject::disconnect(button, SIGNAL(clicked()), this, SLOT(firstCall()));
    QObject::connect(button, SIGNAL(clicked()), this, SLOT(secondCall()));
}

void SignalSlotChange::secondCall()
{
    QMessageBox::information(this, "SignalSlotChange", "Second call", QMessageBox::Ok, QMessageBox::NoButton);
}


int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    SignalSlotChange ssc;
    return app.exec();
}

按下按钮后,将调用初始化插槽firstCall()。对于后续信号,它将信号槽连接更改为secondCall()

我这样做的问题在于它是高度耦合的,并且要求插槽知道确切的方法和信号来改变它。

使用QObject::sender()我会知道发件人的来源但不知道它的信号,我会知道只有一个发件人碰巧发出了这个信号。

我可以用布尔值first_call来做,但这会检查所有后续调用的布尔值,这是我想要避免的,因此这个问题。

1 个答案:

答案 0 :(得分:1)

使用指向成员的方法可以实现一个稍微不同的解决方案:

<强> SignalSlotChange.h

#ifndef SIGNALSLOTCHANGE_H
#define SIGNALSLOTCHANGE_H

#include <QtGui>

class SignalSlotChange : public QWidget {
Q_OBJECT


public:
    SignalSlotChange(QWidget *parent = 0);

private slots:
    void callCall();

private:
    void (SignalSlotChange::* delegate) (); 

    void firstCall();
    void secondCall();

    QPushButton *button;

};

#endif // SIGNALSLOTCHANGE_H

<强> SignalSlotChange.cpp

#include "SignalSlotChange.h"

SignalSlotChange::SignalSlotChange(QWidget *parent) : QWidget(parent) {
    delegate = &SignalSlotChange::firstCall;

    button = new QPushButton("Messgage", this);
    QObject::connect(button, SIGNAL(clicked()), this, SLOT(callCall()));
    show();
}

void SignalSlotChange::callCall() {
    (this->*delegate) ();
}

void SignalSlotChange::firstCall() {
    QMessageBox::information(this, "SignalSlotChange", "First call", QMessageBox::Ok, QMessageBox::NoButton);

    // Change the effective signal-slot connection to secondCall()
    delegate = &SignalSlotChange::secondCall;
}

void SignalSlotChange::secondCall() {
    QMessageBox::information(this, "SignalSlotChange", "Second call", QMessageBox::Ok, QMessageBox::NoButton);
}


int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    SignalSlotChange ssc;
    return app.exec();
}

我不确定这是否是从解耦角度来看更好的解决方案,但优点是该机制不需要了解实际触发的插槽的任何信息。实现“方法切换”的完整逻辑封装在SignalSlotChange类中。 callCall()插槽可以连接到任何其他兼容信号,方法开关仍可正常工作,无需进一步更改代码。