Qt 何时调用异步QMenu::popup()与同步QMenu::exec()?

Qt 何时调用异步QMenu::popup()与同步QMenu::exec()?,qt,qt5,Qt,Qt5,,我注意到QLabel::contextMenuEvent()使用这种(非阻塞)样式: 或者,我在Qt代码示例中看到了这种(阻塞)样式: QMenu *menu = ... // Blocking QAction* action = menu->exec(event->globalPos()); // Or before menu->exec() call: menu->setAttribute(Qt::WA_DeleteOnClose) delete menu; 我可

,我注意到
QLabel::contextMenuEvent()
使用这种(非阻塞)样式:

或者,我在Qt代码示例中看到了这种(阻塞)样式:

QMenu *menu = ...
// Blocking
QAction* action = menu->exec(event->globalPos());
// Or before menu->exec() call: menu->setAttribute(Qt::WA_DeleteOnClose)
delete menu;
我可以看出这些区别:

  • 非阻塞vs阻塞
  • 返回
    void
    vs
    QAction*
他们还有其他的区别吗?示例:非阻塞是否有优势,例如,事件循环可以处理其他事件?如果差异是纯粹的风格,请让我知道


最后,我注意到在GNU/Linux/KDE上调试非阻塞样式对我来说有点奇怪,但这可能与此无关。

我可以在您的观察中添加以下内容:

通过查看的源代码,可以清楚地看出,该方法优于
QMenu::popup
,这意味着它扩展了其功能,即通过添加事件循环:

QAction *QMenu::exec(const QPoint &p, QAction *action)
{
    ...
    QEventLoop eventLoop;
    d->eventLoop = &eventLoop;
    popup(p, action);
    ...
    (void) eventLoop.exec();
    ...
    d->eventLoop = nullptr;
    return action;
}
有效地,这使得处理
exec
-uted
QMenu
更像是
QDialog
(这意味着它是模态的,您可以直接将结果作为返回值获得),而
弹出窗口更像是常规的
QWidget
,其结果通过信号和插槽获得。当然,您可能会把这称为编程风格的问题,但根据应用程序的不同,与
QMenu::exec
相比,
QMenu::popup
的低级访问可能更合适

何时调用QMenu::popup()与QMenu::exec()

前者:永远。后者:永远不会。就这么简单

为什么??因为重新进入事件循环会导致意大利面代码。这个世界是异步的,你不能假装你在“等待”同步代码中的东西,而这个世界在继续,做着各种各样的事情,这种代码风格对你来说是隐藏的。
exec()
调用实际上意味着“运行我的应用程序的任意部分,直到用户确定他们已经受够了弹出窗口的不确定时间”。如果这听起来令人讨厌,那么它的意思是:这是一种令人讨厌的、有缺陷的、可怕的开发UI代码的方式,并且会导致难以调试的错误,并且允许您拖延时间,而不是花时间以异步方式实现。我感到震惊的是,Qt项目仍然在其代码示例中提供了这一点
exec()
是禁止的。由于Qt平台特定代码的破坏,很少有情况需要使用它。例如,Qt(上次我检查时)没有费心在MacOS上实现主runloop的
QDrag
支持,所以他们在本地启动了一个runloop,只是因为苹果的示例代码显示了同样的愚蠢,而这可以在没有AFAIK的情况下完成(虽然nbot很琐碎——但这是库代码,不应该总是琐碎的——否则用户可以自己做)


您可以使用状态机(
QStateMachine
)来指定应用程序的行为,在特定弹出窗口可见时具有专用状态,然后您可以在应用程序退出该状态时执行必要的响应。您还可以使用C++20协程编写Qt ui代码,并使用一些脚手架代码来实现这一点(Qt还没有提供任何信息)。

这里描述了主要的区别:我写这篇评论时非常诚实和尊重:我必须阅读你的回答好几遍,才能理解你所写的内容!起初,我认为你的回答包含了sync
exec()
和async
popup()之间的输入错误
。后来,我意识到你说的是sync
exec()
实际上是在向开发人员隐瞒事情!我作为一个非常普通的开发人员编写GUI已经有20年了,从来没有想过这个想法。谢谢你开门!看来@scopchanov的建议正好相反。你能评论一下吗?我很重视你的意见。@kevinarpe,KubaOber非常有经验我非常重视他的意见。我建议你将这个答案标记为已被接受。@scopchanov哦,我可能也非常有经验以错误的方式做事:)但是,一般来说,任何一个交互式的甚至是网络应用程序的异步性质都会引起很大的麻烦——我已经多次遇到过这种情况,我习惯于强烈反应,因为它从来没有,一次也不能很好地结束。一旦QT支持现代C++异步代码,这将变得更容易处理。(
co_wait
和朋友)。这将允许编写具有定义良好的异步行为且在等待时没有线程阻塞的直线代码。很抱歉我的回复太晚了。看来@UnslanderMonica的建议正好相反。请您发表意见好吗?我很重视您的意见。@kevinarpe,我不认为完全相反。我不主张
exec
更好。我使用了“可能”和“视情况而定”这两个词。我的回答是有效的,因为它显示了源代码中的事实。几乎没有分析。另一方面,库巴伯的回答侧重于分析。我认为没有冲突。无论如何,我更喜欢他的回答,我建议你接受它。@kevinarpe只是为了澄清-
superior
并不意味着更好。它意味着它扩展了
弹出窗口的功能,即做更多的事情。
QAction *QMenu::exec(const QPoint &p, QAction *action)
{
    ...
    QEventLoop eventLoop;
    d->eventLoop = &eventLoop;
    popup(p, action);
    ...
    (void) eventLoop.exec();
    ...
    d->eventLoop = nullptr;
    return action;
}