如何让Windows认为您的应用程序仍然很忙,尽管它没有响应

时间:2011-12-07 08:14:57

标签: windows qt

我的应用程序是一个窗口应用程序,它执行某些复杂的数学算法。因为我很久以前就开始使用该应用程序,所以大多数仍然是单线程的。更确切地说,主线程执行所有复杂的计算逻辑。值得一提的是,在计算过程中,我在屏幕上显示了一些进展。

在大多数情况下,数学算法只需要几秒钟,因此在用户启动操作后,会显示沙漏(或Windows 7中的运行圆圈),几秒钟后会显示结果。

在某些情况下,算法可能需要几分钟时间。在此期间,我显示了沙漏,当算法繁忙时,我会在窗口中显示进度。但是,如果用户在忙碌一段时间后点击应用程序,则窗口变得“更白”(好像在窗口上放置了一块非完全透明的塑料),窗口不再更新,Windows报告'应用程序没有响应'。

我使用Qt并使用Qt函数QWidget :: repaint在算法繁忙时强制重绘。重漆工作了一段时间,但如上所述,Windows似乎在一段时间后阻止了这一点。

告诉Windows您的应用程序是否仍然处于忙碌状态以便窗口不断更新的正确方法是什么?如果我进入显式消息循环,用户可能会在应用程序中触发我不想要的其他操作。

  • 打电话给PeekMessage就足够了吗?
  • 调用GetMessage就足够了吗?
  • 或者我应该调用DispatchMessage?如何阻止用户启动另一个操作(实际上,阻止所有用户输入)
  • 我每次更新窗口时是否应该拨打其中一条消息,或者我可以限制自己每隔几秒钟调用一次(10秒?,30秒?...)

请注意,目前无法将计算逻辑移至单独的线程。

我在Windows 7上使用Visual Studio 2010,与Qt 4.7结合使用。

4 个答案:

答案 0 :(得分:5)

您应该将GUI与应用程序逻辑分开。所有其他解决方案都是黑客。使用Qt可以轻松地将计算逻辑移动到单独的线程中。

我假设有一个函数(让我们称之为execute()),当被调用时执行所有这些耗时的数学运算。一种选择是使用Qt Concurrent API在单独的线程中调用此函数,而不使用低级线程处理。

您需要的是QtConcurrent::run功能:

  

QtConcurrent :: run()函数在一个单独的线程中运行一个函数。   函数的返回值通过QFuture提供   API。

您可以执行以下操作(让execute()成为A定义的类),而不是简单地调用阻止您的用户界面的execute()

QFuture<void> future = QtConcurrent::run(this, &A::execute);

您可以使用QFutrureWatcher以获得有关功能何时完成的通知。

答案 1 :(得分:1)

你可以不时地拨打QApplication::processEvents(),比如说每2或3秒钟左右。这应该会触发重绘事件并刷新进度条和其他元素。

答案 2 :(得分:1)

类似的问题和很多信息: I need a message pump that doesn't mess up my open window

但是,正如您可能已经知道的那样,这是一个非常黑客的问题,尝试将代码移动到另一个线程会更好。为什么这不是一个选择?

答案 3 :(得分:0)

DisableProcessWindowGhosting函数(参见http://msdn.microsoft.com/en-us/library/ms648415(v=vs.85).aspx)告诉Windows,如果应用程序没有响应,它不能显示“重影窗口”。

我的同事用它做了一些实验并注意到以下几点:

  • 显示进度的动画很好(这实际上是我想要实现的)
  • 用户仍然可以最小化,移动......窗口(很棒)
  • 缺点:如果应用程序真的挂起,用户必须使用任务管理器来终止它

所以,这解决了我的问题。