[英]Modal QProgressDialog updated from worker thread
I want to update a modal QProgressDialog from my worker thread. 我想从我的工作线程更新模态 QProgressDialog。 However, if I set the dialog to be modal, my application crashes (and the dialog did not show any progress).
但是,如果将对话框设置为模式对话框,则我的应用程序将崩溃(对话框未显示任何进度)。 If I do not, everything goes fine (but the user can tinker around with the rest of the program, which may cause issues).
如果我不这样做,一切都会很好(但是用户可以修改程序的其余部分,这可能会导致问题)。
What am I doing wrong? 我究竟做错了什么?
Minimum code sample follows: 最小代码示例如下:
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();
Your thread is pretty much pointless. 您的线程几乎毫无意义。 It serves no real purpose.
它没有真正的目的。 You could have as well just called
QApplication::processEvents
in your read_file
method. 您也可以在
read_file
方法中调用QApplication::processEvents
。 But you shouldn't, calling processEvents
is bad practice. 但是您不应该,调用
processEvents
是不好的做法。
What you should do is remove that while
loop, and make your progress dialog a member of your class. 您应该做的是删除
while
循环,并使进度对话框成为您班级的成员。 I don't really like how that lambda looks either. 我也不很喜欢那个lambda的样子。 I would personally just use
filereader::read_file
as a slot. 我个人只是将
filereader::read_file
用作插槽。
Note that Qt::windowModal
blocks input to the parent window. 注意,
Qt::windowModal
阻止输入到父窗口。 Your progress dialog has no parent. 您的进度对话框没有父级。 So you would either have to call
progress->setModal(true)
, or progress.setWindowModality(Qt::ApplicationModal);
因此,您必须调用
progress->setModal(true)
或progress.setWindowModality(Qt::ApplicationModal);
progress->setModal(true)
. 。 Or set a parent to it.
或为其设置父项。
Here is a small example (it is not tailor made for your application, but it should point you in the right direction): 这是一个小示例(它不是为您的应用程序量身定制的,但应为您指明正确的方向):
#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"
First of all, if you want the progress to be Modal, why do you need to perform the reading of the file in a background thread ? 首先,如果您希望进度为Modal,为什么需要在后台线程中执行文件读取? You can perform your file reading operation in the main (GUI) thread, as long as from time to time you check the cancellation status.
您可以在主(GUI)线程中执行文件读取操作,只要您不时检查取消状态即可。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.