1

我尝试使用 aQProgressDialog给用户一些关于一个长任务的进度的信息,同时允许他取消这个任务。

基本上,我有一个QDialog带按钮的ComputeQDialog通过单击它,会在 my的父级成员上调用一个耗时的方法。这个方法需要一个回调来告诉调用者工作的进度。

问题是进度对话框在出现之前需要一些时间,并且不会立即考虑单击其Cancel按钮。

很明显我的代码有问题,但是我不习惯 Qt,我尝试了很多东西。我可能需要一个单独的线程。

我的代码摘录:

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();
}
4

2 回答 2

4

该对话框不会立即出现,因为您将最短持续时间设置为 500 毫秒。将其设置为 0 以使对话框在进度更改时立即显示或手动调用其显示函数。

为了使取消按钮起作用,请将您的长计算移到另一个线程(例如使用 QThread 或 std::async )并让您的主事件循环继续执行。

实际上,您的代码存在很多问题,但是这两点应该为您指明正确的方向。以我的经验,每次手动调用 processEvents 都会产生很大的代码异味。

于 2018-02-12T10:41:28.293 回答
2

您所做的是尝试使用 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

于 2018-02-12T10:51:00.993 回答