1

I have a use case when user actions initialise application data at each runtime. To represent that behavior here is my sample code:

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();
}

When the button is pressed then the initialising slot firstCall() is called. It changed the signal-slot connection to secondCall() for subsequent signals.

The problem with the way I do it is that it is highly coupled and requires that slot knows exact method and signals to change it.

With QObject::sender() I would know origin of sender but not its signal, and I would know about just one sender which happened to emit that signal.

I can do it with a Boolean first_call but that would be making a check on Boolean value for all subsequent calls, something which I want to avoid and hence this question.

4

1 回答 1

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()插槽可以连接到任何其他兼容信号,并且方法切换仍然有效,无需进一步更改代码。

于 2012-12-03T15:04:19.273 回答