簡體   English   中英

如何在QT5中使用lambda將具有int參數的信號連接到具有enum參數而沒有enum的插槽?

[英]How to connect a signal with int parameter to a slot with enum parameter WITHOUT using lambdas in QT5?

我正在嘗試將QComboBox中的currentIndexChanged(int)信號連接到我的類中接收枚舉的類的插槽,例如Foo::mySlot(EnumFoo)

我知道所有這些方式都不起作用:

  1. connect(cb, &QComboBox::currentIndexChanged, foo, &Foo::mySlot);
  2. connect(cb, static_cast<void (QComboBox::*)(EnumFoo)>(&QComboBox::currentIndexChanged), foo, &Foo::mySlot);
  3. connect(cb, &QComboBox::currentIndexChanged, foo, static_cast<void (Foo::*)(int)>(&Foo::mySlot));

因為在C / C ++中, int永遠不會隱式轉換為枚舉類型。 相反,我認為如果我的信號具有enum參數,則可以毫無問題地將其連接到具有int參數的插槽。

我知道如何使用lambda函數解決此問題:

connect(cb, &QComboBox::currentIndexChanged, [=](int i){ foo.mySlot(static_cast<EnumFoo>(i)); });

沒有lambda函數,有什么方法可以解決此問題?

編輯:使用我提出的解決方案,我以這種方式連接Foo :: mySlot。

LambdaWrapper *lw = new LambdaWrapper;
lw->connect(cb, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [=](int i){ foo.mySlot(static_cast<EnumFoo>(i)); }, foo);

而且我不必擔心斷開連接的問題了。 只需管理lw壽命。

使用一個帶int的中間插槽,並直接調用另一個插槽函數。

class Foo : public QObject
{
    Q_OBJECT:

public slots:
    void IndexChanged(int intParam);    
    void mySlot(EnumFoo fooType);
};    

void Foo::IndexChanged(int index);
{
    EnumFoo fooType = <static_cast<EnumFoo>(index);
    mySlot(fooType);
}

connect(cb, &QComboBox::currentIndexChanged, foo, &Foo::IndexChanged);

我創建了一個小類來自動執行此斷開連接的處理。

lambdawrapper.h

class LambdaWrapper : public QObject {
    Q_OBJECT
public:
    explicit LambdaWrapper(QObject* parent = 0);
    virtual ~LambdaWrapper();

    template<typename Func1, typename Func2>
    void connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender,
                 Func1 signal,
                 Func2 slot,
                 QObject* receiver = 0) {
        connections << QObject::connect(sender, signal, slot);
        helperConnection(receiver);
    }

private slots:
    void disconnectReceiver(QObject* obj);

private:
    void helperConnection(QObject* obj);
    QList<QMetaObject::Connection> connections;
    QObjectList receivers;
};

lambdawrapper.cpp

LambdaWrapper::LambdaWrapper(QObject *parent) : QObject(parent) { }

LambdaWrapper::~LambdaWrapper() {
   for (const QMetaObject::Connection& c : connections)
       QObject::disconnect(c);
}

void LambdaWrapper::disconnectReceiver(QObject *obj) {
    if (receivers.contains(obj)) {
        QList<const QMetaObject::Connection*> toRemove;
        const int n = receivers.size();
        for (int i=0; i<n ; ++i) {
            if (receivers.at(i) == obj) {
                disconnect(connections.at(i));
                toRemove << & connections.at(i);
            }
        }

        receivers.removeAll(obj);
        for (const QMetaObject::Connection* c : toRemove)
            connections.removeAll(*c);
    }
}

void LambdaWrapper::helperConnection(QObject* receiver) {
    receivers << receiver;
    if (receiver) QObject::connect(receiver, &QObject::destroyed, this, &LambdaWrapper::disconnectReceiver);
}

因此,您要做的就是將此類實例化到您的主QWidgetQMainWindowQDialog派生類中。

foo.h
....
class Foo : public QMainWindow
....
private:
    LambdaWrapper* lw;
....

foo.cpp
.... 
lw = new LambdaWrapper(this);
QCheckBox *ck = new QCheckBox("check");
lw->connect(ck, &QAbstraceButton::toggled, [=](bool b){ /* do stuff */}, 0);
....

connect成員的第4個參數是可選的,它表示一些在lambda內部調用的QObject指針(如果在已刪除該對象的情況下調用lambda,則可能會使程序崩潰)。 如果傳遞此參數,則其銷毀信號將連接到LambdaWrapper中的插槽,以確保在銷毀該接收機時,與該接收機的所有連接都將斷開。

這很臟,但是解決了我的問題。 現在,我可以直接連接到lambda,而不必擔心斷開它們的連接。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM