我尝试使用QProgressDialog
向用户提供有关长任务进度的一些信息,同时允许他取消此任务。
基本上,我有QDialog
个按钮Compute
。点击它,我的QDialog
父母的成员就会调用一个耗时的方法。此方法采用回调来告诉调用者工作进度。
问题是进度对话框在显示之前需要一些时间,并且没有立即考虑点击其Cancel
按钮。
我的代码摘录:
void MyDialog::callbackFunction(int value, void * objPtr) {
((QProgressDialog *)(objPtr))->setValue(value);
QCoreApplication::processEvents();
}
void MyDialog::on_mComputeBtn_clicked()
{
Compute();
}
void MyDialog::Compute()
{
QProgressDialog progressDialog("Optimization in progress...", "Cancel", 0, 100, this);
progressDialog.setMinimumDuration(500); // 500 ms
progressDialog.setWindowModality(Qt::WindowModal);
progressDialog.setValue(0);
connect(&progressDialog, SIGNAL(canceled()), this, SLOT(Cancel()));
QCoreApplication::processEvents();
parentMember->LongComputation(callbackFunction);
// probably useless
progressDialog.reset();
progressDialog.hide();
QCoreApplication::processEvents();
}
答案 0 :(得分:3)
由于您将最短持续时间设置为500毫秒,因此对话框不会立即显示。将其设置为0可使对话框立即显示进度更改或手动调用其显示功能。
为了使取消按钮工作,将长计算移动到另一个线程(例如使用QThread或std :: async)并让主事件循环继续执行。
实际上你的代码存在很多问题,但这两点应该指向正确的方向。根据我的经验,每次手动调用processEvents都会产生很大的代码味道。
答案 1 :(得分:1)
你所做的是尝试使用QProgressdialog的模态范例,不要让主事件泵发射,你也设置0.5秒超时,最小持续时间将确保暂停。也许无模式变体更适合你的情况。
如果进程有不连续的步骤,你可以在没有单独的线程
的情况下完成class MyTask : public QObject
{
Q_OBJECT
public:
explicit MyTask(QObject *parent = 0);
signals:
public slots:
void perform();
void cancel();
private:
int steps;
QProgressDialog *pd;
QTimer *t;
};
...
void MyDialog::on_mComputeBtn_clicked()
{
myTask = new MyTask;
}
...
MyTask::MyTask(QObject *parent) :
QObject(parent), steps(0)
{
pd = new QProgressDialog("Task in progress.", "Cancel", 0, 100000);
connect(pd, SIGNAL(canceled()), this, SLOT(cancel()));
t = new QTimer(this);
connect(t, SIGNAL(timeout()), this, SLOT(perform()));
t->start(0);
}
void MyTask::perform()
{
pd->setValue(steps);
//... perform one percent of the operation
steps++;
if (steps > pd->maximum())
t->stop();
}
void MyTask::cancel()
{
t->stop();
//... cleanup
}
QThread示例存在于此处:Qt 5 : update QProgressBar during QThread work via signal