【发布时间】:2018-02-22 16:43:05
【问题描述】:
我正在使用 Qt 5.9.2 和 Visual Studio 2015 和 QtDesigner 来编写 Windows GUI 应用程序。我尝试通过以下调用连接我的一项操作:
connect(ui.myAction, &QAction::triggered, memberPtrToObjX_, &ClassX::Run);
但是,在单击菜单栏中的 myAction 后,并不总是触发 ClassX::Run。调查这个问题,我想,使用 lambda 语法的相同信号槽连接是有效的:
connect(ui.myAction, &QAction::triggered, [this](bool run) { memberPtrToObjX_->Run(run); });
我很确定,这两个调用在语法上都是正确的。除了两个调用都返回一个有效的QMetaObject::Connection,如果我保存返回值并使用运算符 bool() 进行检查。
显然我可以坚持使用有效的 lambda 版本,但我很困惑,更愿意知道我的“解决方案”背后的原因。这两个调用之间是否有任何功能差异,可以解释不同的行为?
【问题讨论】:
-
我看到的唯一区别是:在第一个版本中,使用
memberPtrToObjX_中的当前指针(在connect()时)(总是)。第 2 版在触发信号时使用memberPtrToObjX_中的当前指针。如果在connect()之后修改memberPtrToObjX_- 这会有所不同。 -
第二种形式总是会产生
Qt::DirectConnection而不是Qt::AutoConnection类型的连接,这意味着发射器和接收器必须始终在同一个线程上(一般来说)。 -
@Scheff 谢谢!这是一个很好的观点,从理论上回答了我的问题。不幸的是,它不是这里的解决方案。事实上,我很确定,指针没有改变。我通过将我的 lambda 调用更改为
connect(ui.myAction, &QAction::triggered, [memberPtrToObjX_](bool run) { memberPtrToObjX_->Run(run); });非常满意。现在memberPtrToObjX_应该被复制捕获,类似于第一个版本。但仍然始终触发 ClassX::Run。 -
你能提供一个minimal reproducible example吗?如果
memberPtrToObjX_没有修改并且它的指针lives in同一个线程,第一个和第二个版本应该没有区别。 (在这种情况下,第一个connect()会将Qt::AutoConnection解析为Qt::DirectConnection。这实际上是@G.M. 已经暗示的。)否则,(指针“住在”另一个线程中)然后......我相信,在这个情况下,第二个版本是一个“定时炸弹”,似乎效果更好。 -
出于好奇:你确定
checkedarg. (在QAction::triggered(bool checked))没有任何意想不到的效果吗? (我只是问,因为我不知道您的QAction是如何配置的,以及您在ClassX::Run(bool)中对checked做了什么。)尽管如此,它仍然无法解释connect()s 的不同行为......
标签: qt lambda connect signals-slots