2014-10-24 3 views
1

Я написал в C++ решатель для игры с 8 играми, и теперь я пытаюсь использовать Qt, чтобы дать ему графический интерфейс.Qt - GUI freezing

В принципе у меня есть базовый объект типа «Board», который представляет собой панель головоломки, и я организовал графический интерфейс в виде сетки QPushButton. Затем у меня есть метод updateUI, который связывает каждой кнопке правильный текст, основанный на плате. Что-то вроде

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-> решить) занимает некоторое время. Затем я получаю список выполненных ходов, в решенииMoves, и то, что я хотел бы сделать, это показать это движение на доске с некоторой задержкой между движением и следующей. Этот метод вызывается мой основной, который выглядит следующим образом:

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

return app.exec(); 

Результатом является то, что GUI зависает и через какое-то время, он отображает только решение, полностью пропуская ходы.

Что мне не хватает? Спасибо!

P.S. Я не думаю, что мне нужен другой Thread для решателя, потому что я хочу, чтобы решатель выполнил до. Это правильно?

+0

UI основаны на событиях (это касается уровня ОС, это не Qt-вещь).Вам нужно переконфигурировать вашу функцию решения, чтобы вместо спящего сразу же после ее решения возвращалась; то вы можете настроить таймер (который предоставляет события в потоке пользовательского интерфейса), чтобы отображать перемещения по одному, не забивая поток пользовательского интерфейса. – Cameron

+0

Не знаю, понял ли я, что вы сказали о перепроектировании моей функции решения ... То, что она делает, это в основном расширение узлов дерева поиска до достижения цели, и оно работает: в среднем требуется всего несколько миллисекунд. Затем, * после *, я хотел бы начать показывать движения. – minomic

+0

Я имел в виду ваш метод 'solveGUI', извините за путаницу. – Cameron

ответ

1

Это app.exec(), который фактически запускает основной цикл, который обрабатывает все события, включая отображение GUI. Если вы хотите позвонить solve(), это нормально, но если вы хотите отображать и обновлять графический интерфейс пользователя до exec(), это неправильно. Я не уверен, что это абсолютно невозможно, но это определенно не правильный способ сделать это.

Существует два пути. Более канонический способ - перепроектировать программу, используя QTimer. Тогда все будет плавным и отзывчивым. Но иногда это бывает утомительно. В вашем случае это должно быть довольно легко. Просто сохраните результаты где-нибудь и вызовите слот, используя объект QTimer каждые 1000 секунд - он будет иметь тот же эффект, что и ваш Sleep(), но сохранит все отзывчивое.

Другим решением является вызов вашего метода solveGUI() после того, как exec() начинает свою работу. Это может быть сделано, например, с помощью QTimer::singleShot():

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

Затем перед каждым Sleep(), вы должны вызвать QApplication::processEvents(), которая в основном позволяет временной контроль выхода, обработка всех ожидающих событий, включая обновления GUI. Этот подход несколько проще, но он уступает, так как GUI все же зависает на каждом Sleep(). Например, если пользователь хочет выйти из приложения или если окно необходимо перекрасить, это вызовет неудобные задержки в графическом интерфейсе.

+0

Я использовал QTimer, и теперь все работает нормально. Спасибо. – minomic

1

Вы останавливаете основной поток (который также обрабатывает события) и не реагирует на сообщения клавиатуры/мыши/окна.

Вы должны использовать асинхронную операцию таймера вместо функции ожидания: используйте QTimer, чтобы отложить показ следующего решения и не оставлять сообщения без ответа слишком долго.