如何使用en参数将带有int参数的信号连接到具有枚举参数的插槽而不使用QT5中的lambdas?

时间:2015-12-16 12:24:20

标签: c++ qt lambda signals-slots

我尝试将来自currentIndexChanged(int)的信号QComboBox连接到我的班级中接收枚举的广告位,例如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));
  4. 因为在C / C ++中,int从不隐式转换为枚举类型。反之亦然,我想如果我的信号有一个枚举参数,我可以将它连接到带有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生命周期。

2 个答案:

答案 0 :(得分:1)

使用带有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);

答案 1 :(得分:0)

我已经创建了一个小类来自动执行这个断开连接的东西处理。

lambdawrapper.h

Laravel Framework version Lumen (5.1.6) (Laravel Components 5.1.*)

lambdawrapper.cpp

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::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); } QWidgetQMainWindow派生词。

QDialog

connect成员的第四个参数是可选的,它代表一些在lambda内部调用的QObject指针(如果在已经删除了该对象的情况下调用lambda,则会导致程序崩溃)。如果您传递此参数,则其已销毁的信号将连接到LambdaWrapper中的一个插槽,以确保在此接收器被销毁时将断开与此接收器的所有连接。

这很脏,但解决了我的问题。现在我可以直接连接到lambdas,不必担心断开它们。