Модальный QProgressDialog обновлен из рабочего потока

Я хочу обновить модальный QProgressDialog из моего рабочего потока. Однако, если я установил диалоговое окно на модальное, мое приложение вылетает (и диалог не показывал никакого прогресса). Если нет, все идет хорошо (но пользователь может поработать с остальной частью программы, что может вызвать проблемы).

Что я делаю неправильно?

Ниже приведен минимальный пример кода:

filereader qfr;

QProgressDialog progress("Importing file.", "Cancel", 0, file_size);

connect(&qfr, &filereader::signalProgress, &progress, &QProgressDialog::setValue, Qt::QueuedConnection);

QThread worker_thread;

std::atomic<bool> success = false;

connect(&worker_thread, &QThread::started,
[&]() {
success = qfr.read_file(/* parameters */);
worker_thread.quit();});

worker_thread.start();

//progress.setWindowModality(Qt::WindowModal); // Works only fine when this line is commented !!

while (worker_thread.isRunning()) {
QApplication::processEvents();
QThread::sleep(0);
}

progress.close();

0

Решение

Ваша тема в значительной степени бессмысленна. Это не служит никакой реальной цели. Вы могли бы просто позвонить QApplication::processEvents в вашем read_file метод. Но ты не должен звонить processEvents это плохая практика.

Что вы должны сделать, это удалить это while цикл, и сделать ваш диалог прогресса членом вашего класса. Мне не очень нравится, как выглядит эта лямбда. Я бы лично просто использовал filereader::read_file как слот.

Обратите внимание, что Qt::windowModal блокирует ввод в родительское окно. У вашего диалога прогресса нет родителя. Так что вам придется либо позвонить progress->setModal(true), или же progress.setWindowModality(Qt::ApplicationModal);, Или установить родителя к нему.

Вот небольшой пример (он не сделан специально для вашего приложения, но он должен указывать вам правильное направление):

#include <QtWidgets>

class Worker : public QObject
{
Q_OBJECT
public:
Worker(QObject *parent = nullptr) : QObject(parent){}
public slots:
void simulateLongProcess()
{
for(int i = 0; i < 101; i++)
{
emit progressChanged(i);
QThread::msleep(100);
}
emit finishedWorking(true);
}
signals:
void progressChanged(int progress);
void finishedWorking(bool result);
};

class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr) : QWidget(parent)
{
setLayout(new QHBoxLayout);
progress_dialog.setModal(true);
progress_dialog.setAutoReset(false);
progress_dialog.setCancelButton(nullptr);
QThread *thread = new QThread(this);
connect(thread, &QThread::started, &worker, &Worker::simulateLongProcess);
connect(&worker, &Worker::finishedWorking, thread, &QThread::quit);
connect(&worker, &Worker::progressChanged, &progress_dialog, &QProgressDialog::setValue);
connect(&worker, &Worker::finishedWorking, &progress_dialog, &QProgressDialog::close);
connect(&worker, &Worker::finishedWorking, this, &Widget::handleResult);
QPushButton * start_button = new QPushButton("START");
connect(start_button, &QPushButton::clicked, this, [=]
{
progress_dialog.show();
thread->start();
});
layout()->addWidget(start_button);
resize(400, 300);
}

public slots:
void handleResult(bool result)
{
// do something with the result
}

private:
QProgressDialog progress_dialog;
Worker worker;
};

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}

#include "main.moc"
1

Другие решения

Прежде всего, если вы хотите, чтобы прогресс был модальным, зачем вам выполнять чтение файла в фоновом потоке? Вы можете выполнять операции чтения файлов в основном потоке (GUI), если время от времени вы проверяете статус отмены.

0

По вопросам рекламы [email protected]