问题
在 QT 的 UI 编程中, 如果有一个函数消耗的时间特别长, 并且运行于主线程, 那么界面的响应会很不灵敏. 通常的作法是使用多线程编辑.
另外, 如果该函数执行时间很长, 为了通知任务的进度, 一般会使用进度条. 但有时候无法准确的使用进度条, 比如在数据库操作中, 为了提高读写数据库的性能, 通常会采用事务操作, 多个读写数据库的操作合并成了一个事务, 此时如何设置进度条的进度值?
此时, 可以使用 QtConcurrent 和 QFutureWatcher 来解决这个问题. 对于第一个问题不需多言. 对于第二个问题, 可以在任务开始后以QMessageBox::imformation 对话框来告知用户完成任务需要时间很长, 在任务执行完毕时关闭该对话框 (如果用户没有关闭的话).
QtConcurrent 和 QFutureWatcher
QtConcurrent 是一个名字空间, 其内包含了众多的高级 API, 方便用户编写多线程程序.
QFutureWatcher 可以用于监视线程的完成情况, 并获取线程的返回值.
QtConcurrent 线程函数与 QFutureWatcher 之间的中间者是 QFuture.
示例代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFutureWatcher>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
//
void busy_job();
private:
//
int do_busy_job();
//
void busy_job_finished();
private:
Ui::MainWindow *ui;
//
QFutureWatcher<int>* watcher_;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtConcurrent>
#include <QFuture>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//
watcher_ = new QFutureWatcher<int>;
connect(watcher_, &QFutureWatcher<int>::finished,
this, &MainWindow::busy_job_finished);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::busy_job()
{
// 若有需要, 启动告知对话框
auto future = QtConcurrent::run(this, &MainWindow::do_busy_job);
watcher_->setFuture(future);
}
int MainWindow::do_busy_job()
{
return 1;
}
void MainWindow::busy_job_finished()
{
// 若有需要, 关闭通知对话框
qDebug() << "busy job finished!";
qDebug() << "the returned value is: "
<< watcher_->result();
}
调用
MainWindow w;
w.busy_job();
输出
busy job finished!
the returned value is: 1