在不调用QApplication::exec()的情况下显示小部件的正确方式是什么



出于测试目的,我想创建并显示一个小部件。现在我只需要小部件正确渲染,但将来我可能想扩展它,所以我模拟各种事件来查看小部件的行为。

从各种来源来看,以下内容似乎应该有效:

QApplication app;
QPushButton button("Hello");
button.show();
// Might also be necessary:
QApplication::processEvents();

但对我来说,小部件无法正确呈现。创建一个窗口来显示小部件,但是它是完全黑色的。

我可以通过添加以下行使小部件正确渲染:

std::this_thread::sleep_for(std::chrono::milliseconds(10));
QApplication::processEvents();

10毫秒大约是使小部件正确渲染所需的最小时间。

有人知道如何在没有时间延迟的情况下实现这一点吗?或者知道为什么需要延迟吗?

要测试Qt GUI应用程序,至少需要处理QApplication实例和事件循环。最快的方法是使用QTEST_MAIN宏,这个答案很好地解释了它的确切作用。然而,为了具有更大的灵活性(例如使用GTest、GMock(,您也可以简单地在测试主中创建QAplication实例(无需调用exec(。

然后,要处理事件,您应该调用QTest::qWait。这将在指定的时间内处理您的事件。使用接受谓词的qWaitFor是一种很好的做法,这样可以避免测试中的竞争条件。

在特定的场景中,当您期望发出一些信号时,您也可以使用类似的QSignalSpy::wait功能。

当我们想等到一些参数从一个项目传递到另一个项目时的小例子:

QSignalSpy spy(&widget1, &Widget1::settingsChanged);
widget2->applySettings();
ASSERT_TRUE(spy.wait(5000));
// do some further tests based on the content of passed settings

为什么不让应用程序运行exec?显示窗口小部件的过程不是"窗口小部件";静态";。你不会"draw";屏幕上的小部件,但您有一个应用程序,可以侦听各种事件并从窗口管理器接收draw事件。应用程序只能在窗口管理器要求时绘制小部件。

您的第二个代码工作的原因是您等待窗口管理器发送";draw";在您的条件下请求。这并不能保证它永远有效。

如果你想保证小部件的显示,你需要开始一个循环,直到你至少收到一个抽奖事件,但即使这样也不是万无一失的。

正如Vincent Fourmond熟练地描述的那样,小部件不是一次性的。GUI是非阻塞的,为此,它需要在事件循环中运行。

exec()方法启动这个通过轮询模拟的事件循环。虽然可以将Qt的事件循环与其他事件循环相结合,但我建议您使用一个更简单的解决方案:

在事件循环中通过在程序启动时调用一个方法来继续执行程序在这里找到一个关于如何做到这一点的好答案:https://stackoverflow.com/a/8877968/21974

正如您提到的单元测试,还有一个信号可以用于在生命周期结束时(在小部件被销毁之前(进行检查:QApplication::aboutToQuit。这将在最后一个窗口关闭时发生(以编程方式或由用户关闭(。

最新更新