У меня есть сигнал от цикла (который делает некоторые вычисления), который запускает обновление индикатора выполнения, который находится в главном графическом интерфейсе, после завершения цикла индикатор выполнения обновляется до 100% (индикатор выполнения становится скрытым после завершения процесса), но затем есть задержка, индикатор выполнения остается на 100%, а иногда мышь становится занятой, и только через несколько секунд индикатор выполнения становится скрытым (указывает, что задержка заканчивается), после этого цикла ничего не происходит, поэтому я ничего не могу думает может сделать эту задержку.
Сигнал излучения находится внутри класса в логическом слое, я должен попробовать что-то, включая <QtGui/QApplication>
в этот класс (что звучит для меня не правильно, так как это логический уровень, так зачем ему нужны библиотеки QtGui, но я только что-то тестирую), я поместил следующий код qApp->processEvents();
внутри цикла, и теперь кажется, что все работает задушено, нет занятой мыши, но все равно есть задержка (единственное, что я могу реагировать с GUI, пока происходит эта задержка, но нет обновленных результатов, пока эта задержка не закончится).
Из-за теста с processEvents()
Я думал, что это что-то, связанное с потоками, но если это так, как я могу исправить поведение задержки, конечно, если кто-то думает, что это может быть что-то еще, пожалуйста, сообщите.
Пример кода:
Класс логического слоя:
#include <QtGui/QApplication>
...
processMethod(...)
{
Loop(...)
{
qApp->processEvents();
emit processBarSignle(value);
...some calculations...
}
emit processBarSignle(100);
}
Вид слоя (MainWindow):
on_btn_nextProcess_clicked()
{
m_ui->pBar_process->setVisible(true);
LogicClass->processMethod(...);
m_ui->pBar_process->setVisible(false);
}
Спасибо
Попробуйте следующее:
#include <QtCore/QCoreApplication>
...
processMethod(...)
{
Loop(...)
{
emit processBarSignle(value);
QCoreApplication::processEvents();
...some calculations...
}
emit processBarSignle(100);
QCoreApplication::processEvents();
}
processEvents()
статический метод QCoreApplication, так достаточно включить только QCoreApplication
которая является частью QtCore
библиотека.
Кроме того, вы должны добавить processEvents()
после обновления индикатора выполнения, а не до этого.
Обратите внимание, что processEvents()
не возвращается, пока не будет обработано каждое событие в очереди событий Qt. Если есть, например, Cancel
Кнопка, вам придется проверить, действительно ли пользователь отменил операцию каждый раз, когда вы звонили processEvents()
,
Вы можете исключить пользовательские события, такие как щелчки мыши / нажатия клавиш, используя
QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents )
но это не позволит нажимать что-либо (например, кнопку «Отмена»), когда цикл активен.
Как дальнейшее примечание: это должно называться «processBarSi нг le «;-)
Уточнение по темам и т.д:
Весь ваш цикл и любые щелчки мышью и т. Д. Выполняются только в одном потоке. Если вы позвоните emit()
, slot
что связано с этим signal
выполняется мгновенно (если слот не был на самом деле в другом потоке). А пока цикл не продолжается!
Когда слот закончится, ваш цикл продолжится. В моем примере это означает processEvents()
будет вызван. Теперь, если ваш слот обновил индикатор выполнения или сделал что-то еще, что вызвало перерисовку, в очереди событий будет событие перерисовки, и теперь эта перерисовка произойдет.
Если вы выполните processEvents()
перед вызовом вашего слота не будет никакого события перерисовки, которое можно было бы обработать в этот момент.
Еще раз, цикл не продолжается до processEvents()
полностью сделано. Когда все ожидающие события были обработаны, цикл продолжается с вашими расчетами.
В вашем примере кода фактически есть только один поток. когда on_btn_nextProcess_clicked()
вызывается, показывает индикатор выполнения, затем запускается processMethod()
в той же теме. В идеале вы хотите разделить ваш пользовательский интерфейс и логику обработки данных.
В инициализации создайте отдельный QThread
, запустите его и переместите объект LogicClass в этот поток, вызвав logicClassObject-> moveToThread ([ваш новый поток]). Затем поверните processMethod()
в слот, создайте startProcessing()
сигнал в MainWindow и соедините их. Наконец, создайте processingDone()
слот в MainWindow
и finishedProcessing()
слот в LogicClass
и соединить их. Когда все это настроено, вы можете изменить свой код следующим образом:
void LogicClass::processMethod(...)
{
Loop(...)
{
emit processBarSignal(value);
...some calculations...
}
emit processingDone();
}
void MainWindow::on_btn_nextProcess_clicked()
{
m_ui->pBar_process->setVisible(true);
emit startProcessing(...);
}
void MainWindow::finishedProcessing()
{
m_ui->pBar_process->setVisible(false);
}
Всякий раз, когда вы подключаете сигналы и слоты из двух отдельных потоков, многопоточность сохраняется автоматически. Излучение сигнала в одном потоке приводит к тому, что в другом очереди возникает событие, которое вызывает слот только после того, как второй поток восстановит управление.
В этом случае поток пользовательского интерфейса запланирует событие в потоке обработки, чтобы начать обработку. Затем поток обработки будет постоянно планировать обновления значений progressBar и, наконец, планировать событие, чтобы отключить индикатор выполнения после его завершения. Два потока будут работать в соответствии с планировщиком потока ОС, и обработка не будет блокировать пользовательский интерфейс.