Qt - GUI冻结

时间:2014-10-24 16:20:08

标签: c++ qt user-interface

我在C ++中为8-puzzle游戏编写了一个求解器,现在我正在尝试使用Qt为它提供GUI。

基本上我有一个类型为“Board”的底层对象代表拼图的板,我已经将GUI组织为QPushButton的网格。然后我有一个方法updateUI,它根据Board将每个按钮与正确的文本相关联。像

这样的东西
    for(int i=0; i<Board::MATRIX_DIM * Board::MATRIX_DIM; i++)
    {
        m_buttons[i]->setText(m_values[i]);
    }

在另一种方法(solveGUI)中我有

void MainWindow::solveGUI()
{
    m_game->solve();
    int solutionDepth = m_game->getSolutionDepth();
    Move *solutionMoves = m_game->getSolutionMoves();
    for(int i=0; i<solutionDepth; i++)
    {
        Move m = solutionMoves[i];
        m_board.performMove(m);     /* perform the move on the Board object */
        updateUI();       /* should update the GUI so that it represents the Board */
        Sleep(1000);
    }
}

第一行(m_game-&gt; solve)需要一些时间。然后我在solutionMoves中获得了所执行动作的列表,我想要做的是在棋盘上显示这个动作,在动作和下一个动作之间有一些延迟。这个方法由我的main调用,如下所示:

QApplication app(argc, argv);
MainWindow w;
w.show();
w.solveGUI();

return app.exec();

结果是GUI挂起,一段时间后,它只显示解决方案,完全跳过移动。

我错过了什么?谢谢!

P.S。我认为我不需要为解算器使用不同的线程,因为我希望解算器在显示解决方案之前运行。是不是?

4 个答案:

答案 0 :(得分:1)

您正在停止主线程(也会执行事件处理)并使其无法响应键盘/鼠标/窗口消息。

您应该使用异步计时器操作而不是休眠功能:使用QTimer来延迟显示下一个解决方案,并避免消息长时间无法应答。

答案 1 :(得分:1)

实际上运行主循环的app.exec()处理所有事件,包括显示GUI。如果您想在此之前致电solve(),那就没关系,但如果您想在exec()之前实际显示和更新GUI,那就错了。我不确定它是否完全不可能,但它绝对不是正确的方法。

围绕它有两种方法。更典型的方法是使用QTimer重新设计程序。然后一切都会顺利和响应。但有时这可能是单调乏味的。在你的情况下,它应该很容易。只需将结果保存在某个地方,然后每隔1000秒使用一个QTimer对象调用一个插槽 - 它将与Sleep()具有相同的效果,但会保持一切响应。

另一种解决方案是在solveGUI()开始工作后调用exec()方法。例如,可以使用QTimer::singleShot()

来完成
QTimer::singleShot(0, &w, SLOT(showGUI()));
return app.exec();

然后,在每个Sleep()之前,您应该调用QApplication::processEvents(),这基本上允许您临时控制权,处理所有待处理事件,包括GUI更新。这种方法有点容易,但由于GUI仍在每个Sleep()冻结,因此效果较差。例如,如果用户想要退出应用程序,或者需要重新绘制窗口,则会导致GUI不舒服。

答案 2 :(得分:0)

在处理循环中有一个不错的article of methods to keep the GUI responsive。如果我认为这不是一个复杂的情况,只需在长的处理循环中插入QCoreApplication::processEvents();

答案 3 :(得分:0)

尝试以下操作:

void MainWindow::Wait(int interval ) {

    QTime timer = new QTime;
    timer.restart();

    while(timer.elapsed() < interval) {
        QApplication::processEvents();
    }

}

...
 
for(...) { 

//wait 1 second (1000 milliseconds) between each loop run at first
Wait(1000);
...

}
...

尚未测试-但应该可以使用!