读取Qt5源代码,我注意到QLabel::contextMenuEvent()使用了这种(非阻塞)样式:
QMenu *menu = ...
menu->setAttribute(Qt::WA_DeleteOnClose);
// Non-blocking
menu->popup(event->globalPos());或者,我从Qt代码示例中看到了这种(阻塞)样式:
QMenu *menu = ...
// Blocking
QAction* action = menu->exec(event->globalPos());
// Or before menu->exec() call: menu->setAttribute(Qt::WA_DeleteOnClose)
delete menu;我可以看到这些差异:
void对QAction*他们还有其他的区别吗?例如:非阻塞是否有优势,例如事件循环可以处理其他事件?如果区别是纯粹的风格,请告诉我。
最后,我确实注意到,在GNU/Linux/KDE上调试非阻塞样式对我来说有点奇怪,但这可能是不相关的。
发布于 2020-09-02 23:22:28
何时调用QMenu::popup() vs QMenu::exec()?
前者:永远。后者:永远不会。就这么简单。
为什么?因为重新输入事件循环会导致意大利面代码。这个世界是异步的,你不能假装你在“等待”同步代码中的某些东西,而这个世界在继续,并且做着这种代码样式对你隐藏的各种事情。exec()调用实际上意味着“运行我的应用程序的任意部分,直到用户决定他们已经经受够了弹出窗口的不确定时间”。如果它听起来很恶心,那么它就意味着:开发UI代码的方式很糟糕、错误、糟糕,导致很难调试的bug,并且允许您拖延,而不是花时间在异步的方式上。令我震惊的是,Qt仍然在他们的代码示例中提供了这一点。exec()是可传播的。很少情况下,由于Qt平台特定代码的中断,必须使用它。例如,Qt没有(上次我检查过)在MacOS上的主运行循环中实现了对MacOS的支持,所以他们只是因为苹果的示例代码显示了同样的愚蠢之处,而将其拆分为本地支持,而不使用AFAIK就可以完成它(尽管它是微不足道的--但又怎样呢,它是库代码,不应该总是琐碎的--否则用户自己就可以这么做)。
您可以使用状态机(QStateMachine)指定应用程序的行为,在特定弹出窗口可见时具有专用状态,然后在应用程序退出该状态时执行必要的响应。您还可以使用C++20协同器编写Qt代码,并使用一些脚手架代码来实现这一点(Qt尚未提供任何代码)。
发布于 2020-09-02 18:30:30
我可以在你的意见中补充以下几点:
看一看QMenu::exec的源代码,就可以清楚地看到,这个方法优于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 (这意味着它是模态的,直接作为返回的值得到结果),而popup-ed QMenu则更像普通的QWidget,其结果通过信号和时隙获得。当然,您可以将此称为编程风格的问题,但根据应用程序的不同,与QMenu::exec相比,QMenu::popup的访问级别越低可能更合适。
https://stackoverflow.com/questions/63303201
复制相似问题