C++ Qt插槽和C++;11兰姆达
我有一个QAction项,初始化如下: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* 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
(aQObject
)停止存在时,不会调用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();
}