1

我有一个使用 wxWidgets 创建的 GUI 应用程序。作为功​​能的一部分,我必须在操作 GUI 窗口的同时运行“任务”。例如,我可以运行代码:

long currentTime = wxGetLocalTime();
long stopTime = wxGetLocalTime() + 3;
while (wxGetLocalTime() != stopTime) {}
wxMessageBox("DONE IN APP");

在这 3 秒的持续时间内,我的应用程序基本上会被冻结,直到显示 wxMessageBox。有没有办法在不使用多个线程的情况下在后台运行?它给我正在开发的应用程序带来了问题。

我想知道是否可以使用某些类型的事件处理。非常感谢任何形式的帮助。

4

3 回答 3

6

在 GUI wx 应用程序中运行耗时任务有 3 种方法:

  1. 到目前为止,最优选的是使用不同的线程。应用程序“非常 GUI 密集型”的解释对我来说真的没有任何意义,我认为如果它的 GUI 强度(无论是什么)阻止您使用后台工作线程,您应该认真重新考虑您的程序设计。如果您确实使用这种方法,它非常简单,但要特别注意线程/程序终止问题。特别是,您需要等待线程完成(如果不需要很长时间运行,则可以接受)或在退出程序之前显式取消它。

  2. EVT_IDLE只要没有其他要处理的事件,就使用事件来执行您的任务。这对于可以分解成足够小块的小任务来说并不算太糟糕,因为您需要能够在处理程序中恢复处理。event.RequestMore()即使没有发生任何事情,也不要忘记调用以继续获取空闲事件。

  3. 最糟糕和最危险的是wxYield()按照另一个答案的建议打电话。起初这看起来很简单,但您稍后会后悔这样做,因为这会在您的代码中创建极其难以调试的重入问题。如果您确实使用它,您需要自己防止任何地方的重入,并且您应该真正了解此功能的确切作用。

于 2012-12-18T13:51:53.190 回答
3

试试这个:

long currentTime = wxGetLocalTime();
long stopTime = wxGetLocalTime() + 3;
while (wxGetLocalTime() != stopTime) {
   wxYield();
}
wxMessageBox("DONE IN APP");
于 2012-12-17T23:47:27.313 回答
3

我知道这对游戏来说已经晚了,但是......

我已经成功地使用了 YEARS 的 EVT_IDLE 方法(最初是在 90 年代使用 Motif)。主要思想是将你的任务分解成小块,每块都调用下一块(想想链表)。执行此操作的机制是使用 CallAfter() 方法(当然是使用 C++)。您只需将“CallAfter()”作为该部分的最后一步,这将允许 GUI 主循环运行另一个迭代,并可能在调用您的下一个部分之前更新 GUI 元素等。只要记住保持碎片小。

使用后台线程真的很好,但可能比你想象的要复杂......最终。只要您知道您在后台处理的数据不会被其他任何东西触及/查看,就可以了。如果你知道是这种情况,那么这就是要走的路。此方法允许 GUI 在后台计算期间保持完全响应(调整窗口大小/移动窗口等)

在任何一种情况下,都不要忘记将适当的 GUI 元素脱敏作为第一步,这样您就不会意外地多次启动相同的后台任务(例如,不小心连续多次单击启动后台线程的按钮) .

于 2015-11-18T14:55:04.047 回答