在模态对话框中防止事件循环阻塞

时间:2018-03-15 15:14:52

标签: c++ qt qdialog qtconcurrent

我正在开发一个用户可以解析一些二进制文件的应用程序。一旦他点击"解析" - 按钮,他首先可以选择一些文件,然后解析。当应用程序正在处理文件时,我想显示一个模态对话框,通知用户有关进度(QProgressBar栏)和已解析的文件(QListView list / listModel)。

我目前的做法是覆盖QDialog-sublcass的exec()方法。这样我就可以打电话了

parseAssistant.exec()

目前的实现如下:

class ParseAssistant : public QDialog { public: int exec(); };

int ParseAssistant::exec()
{
    bar->setMaximum(files.size());

    this->show();
    this->setModal(true);

    for (int i = 0; i < files.size(); i++) {
        PluginTable* table = parser.parse(files[i]);

        // do something with the table
        // saveTableintoDB();

        // update GUI
        // bar->setValue(i);
        // listModel->insertRow(0, new QStandardItem(files[i]));
    }
    this->hide();

    return QDialog::Accepted;
}

此(阻塞)方法运行后,用户已解析所有文件或取消了某处的进度。为了达到这个目的,我尝试在while循环中使用QApplication :: processEvents(由于它只在文件完成解析时才进展)或将重度计算外包给某些QConcurrent实现( :: run,:: mapped)。不幸的是,一旦QFuture完成,我不知道如何将程序流程返回到exec()方法,而不依赖于一些CPU密集的循环,如:

while (!future.isFinished()) { QApplication::processEvents(); }

是否有一种更智能的方法来建立模态对话框,该对话框运行繁重的计算(可能被用户取消)而不会阻止事件循环?

2 个答案:

答案 0 :(得分:2)

我首先不会将Qdialog作为子类,但只需使用QFutureWatcher并将观察者finished信号连接到对话框close,这样:

QDialog d;

QFutureWatcher<void> watcher;
QObject::connect(&watcher, &QFutureWatcher<void>::finished, &d, &QDialog::close);

QFuture<void> future = QtConcurrent::run(your_parse_function);
watcher.setFuture(future);

d.exec();

//control returns here when your_parse_function exits

parse函数可以是QObject派生类中的方法,如下所示:

class Parser : public QObject
{
  Q_OBJECT
public:
    void parse()
    {
        for (int i = 0; i < files.size(); i++) {

            PluginTable* table = parser.parse(files[i]);

            emit fileParsed(i, files.size);

            // ...
        }
    }    
signals:
    void fileParsed(int id, int count);
};

您可以将fileParsed信号连接到所选的插槽,然后相应地设置进度条值。

答案 1 :(得分:0)

我个人的做法是:

  • 创建一个单独的线程并在那里进行处理(QThread; std :: thread也应该这样做)
  • 提供有关当前正在处理的文件的信息
  • 可能是另一个告知%
  • 进展情况的信号
  • 另一个信号通知处理完成,在线程结束之前发出
  • 为您的对话框提供适当的插槽并将它们连接到信号(因为涉及的线程不同,请确保连接类型为Qt::QueuedConnection