Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Qt插槽和C++;11兰姆达_C++_Qt_C++11 - Fatal编程技术网

C++ Qt插槽和C++;11兰姆达

C++ Qt插槽和C++;11兰姆达,c++,qt,c++11,C++,Qt,C++11,我有一个QAction项,初始化如下: QAction* action = foo->addAction(tr("Some Action")); connect(action, SIGNAL(triggered()), this, SLOT(onSomeAction())); 然后onSomeAction看起来像: void MyClass::onSomeAction() { QAction* caller = qobject_cast<QAction*>(sende

我有一个QAction项,初始化如下:

QAction* action = foo->addAction(tr("Some Action"));
connect(action, SIGNAL(triggered()), this, SLOT(onSomeAction()));
然后onSomeAction看起来像:

void MyClass::onSomeAction()
{
    QAction* caller = qobject_cast<QAction*>(sender());
    Q_ASSERT(caller != nullptr);

    // do some stuff with caller
}

但是
调用者
总是空的,因此
Q\u断言
触发。如何使用lambdas获取发送者?

简单的答案是:你不能。或者,您不想(或不需要!)使用
sender()
。只需捕获并使用
操作

//                                Important!
//                                   vvvv
connect(action, &QAction::triggered, this, [action, this]() {
    // use action as you wish
    ...
});
this
指定为functor的对象上下文可确保在操作或
this
(a
QObject
)停止存在时,不会调用functor。否则,函子将尝试引用悬空指针

通常,为传递给
connect
的函子捕获上下文变量时,必须遵守以下规定,以避免使用悬空指针/引用:

  • 指向
    connect
    的源对象和目标对象的指针可以通过值捕获,如上所述。可以保证,如果调用functor,连接的两端都存在

    connect(a, &A::foo, b, [a, b]{});
    
    需要特别注意
    a
    b
    位于不同线程中的场景。不能保证一旦输入函子,某些线程就不会删除任何一个对象

    惯用的说法是,一个对象只在其
    线程()
    中被销毁,或者在
    线程()==nullptr
    的任何线程中被销毁。由于线程的事件循环调用functor,因此对于
    b
    ,空线程从来都不是问题-如果没有线程,functor将不会被调用。唉,对于
    b
    的线程中
    a
    的生命周期没有保证。因此,通过值来捕获操作的必要状态更安全,这样就不必担心
    的生存期

    // SAFE
    auto aName = a->objectName();       
    connect(a, &A::foo, b, [aName, b]{ qDebug() << aName; });
    // UNSAFE
    connect(a, &A::foo, b, [a,b]{ qDebug() << a->objectName(); });
    
  • 对对象的引用同上:

    static D d;
    connect(..., [&d]{});
    
  • 不从
    QObject
    派生的不可复制对象应通过其共享指针按值捕获

    std::shared_ptr<E> e { new E };
    QSharedPointer<F> f { new F; }
    connect(..., [e,f]{});
    
  • QObject
    s位于其他线程中,必须由共享指针或弱指针捕获。它们的父级必须在销毁之前取消设置,否则将进行双重删除:

    class I : public QObject {
      ...
      ~I() { setParent(nullptr); }
    };
    
    std::shared_ptr<I> i { new I };
    connect(..., [i]{ ... });
    
    std::weak_ptr<I> j { i };
    connect(..., [j]{ 
      auto jp = j.lock();
      if (jp) { ... }
    });
    
    I类:公共QoObject{
    ...
    ~I(){setParent(nullptr);}
    };
    std::shared_ptr i{new i};
    连接(…,[i]{…});
    std::弱_ptr j{i};
    连接(…,[j]{
    auto-jp=j.lock();
    如果(jp){…}
    });
    

  • 使用lambdas作为插槽非常简单(例如,对于来自QSpinbox的事件):

    connect(spinboxObject,&QSpinBox::editingFinished,this,[this](){});
    
    但这仅在信号没有重载的情况下有效(这意味着有多个信号具有相同的名称但参数不同)

    connect(spinboxObject,&QSpinBox::valueChange,this,[this](){});
    
    给出一个编译错误,因为存在两个重载信号:valueChanged(int)和valueChanged(const QString&) 因此,有必要确定应使用哪个版本:

    connect(spinboxObject, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [this](int newValue){ });
    
    connect(spinboxObject,static_cast(&QSpinBox::valueChanged),this,[this](int newValue){};
    
    稍微短一点(或可读性更好)是使用:

    connect(spinboxObject,QOverload::of(&QSpinBox::valueChanged),this,[this](int newValue){};
    
    不带“this”上下文,例如来自main():


    @FrankOsterfeld的副本:不完全是,因为在这里你不需要任何像所谓副本中那样的体操。在这里,捕获作为参数提供给
    connect
    的显式可用发送方是一件小事。这既漂亮又简单!答案就在我眼前。非常感谢。
    QPointer<QObject> g { this->parent(); }
    connect(..., [g]{ if (g) ... });
    
    class I : public QObject {
      ...
      ~I() { setParent(nullptr); }
    };
    
    std::shared_ptr<I> i { new I };
    connect(..., [i]{ ... });
    
    std::weak_ptr<I> j { i };
    connect(..., [j]{ 
      auto jp = j.lock();
      if (jp) { ... }
    });
    
    connect(spinboxObject, &QSpinBox::editingFinished, this, [this]() {<do something>});
    
    connect(spinboxObject, &QSpinBox::valueChange, this, [this]() {<do something>});
    
    connect(spinboxObject, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [this](int newValue){ });
    
    connect(spinboxObject, QOverload<int>::of(&QSpinBox::valueChanged), this, [this](int newValue) { });
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        QLabel lbl{"Hello World!"};
        QPushButton btn;
        btn.show();
        lbl.show();
    
        QObject::connect(&btn, &QPushButton::clicked, [&lbl](){lbl.setText("Button clicked");});
    
        return a.exec();
    }