Qt之QFutureWatcher

简介: 简述QFuture 表示异步计算的结果,QFutureWatcher 则允许使用信号和槽监视 QFuture,也就是说,QFutureWatcher 是为 QFuture 而生的。简述详细描述基本使用更多参考详细描述QFutureWatcher 提供了有关 QFuture 的信息和通知,使用 setFuture() 函数开始监视一个特

简述

QFuture 表示异步计算的结果,QFutureWatcher 则允许使用信号和槽监视 QFuture,也就是说,QFutureWatcher 是为 QFuture 而生的。

详细描述

QFutureWatcher 提供了有关 QFuture 的信息和通知,使用 setFuture() 函数开始监视一个特定的 QFuture,函数 future() 则返回由 setFuture() 设置的 future。

为了方便,QFuture 的很多函数可以直接通过 QFutureWatcher 来访问,例如:progressValue()、progressMinimum()、progressMaximum()、progressText()、isStarted()、isFinished()、isRunning()、isCanceled()、isPaused()、waitForFinished()、result() 和 resultAt()。而 cancel()、setPaused()、pause()、resume() 和 togglePaused() 是 QFutureWatcher 中的槽函数。

状态更改由 started()、finished()、cancelled()、paused()、resumed()、resultReadyAt() 和 resultsReadyAt() 信号提供,进度信息由 progressRangeChanged()、progressValueChanged() 和progressTextChanged() 信号提供。

由函数 setPendingResultsLimit() 提供节流控制。当挂起的 resultReadyAt() 或 resultsReadyAt() 信号数量超过限制时,由 future 表示的计算将被自动节流。一旦挂起的信号数量下降到限制以下时,计算将恢复。

示例,开始计算并当完成时获取槽回调:

// 实例化对象,并连接到 finished() 信号。
MyClass myObject;
QFutureWatcher<int> watcher;
connect(&watcher, SIGNAL(finished()), &myObject, SLOT(handleFinished()));

// 开始计算
QFuture<int> future = QtConcurrent::run(...);
watcher.setFuture(future);
AI 代码解读

基本使用

来看一个图像加载和缩放的示例。选择多个图片,进行异步计算(将所有图片进行缩放),加载过程中可以显示进度,以便我们实时了解进展。每当一个图片处理完成,就会显示在窗体中。

这里仅为了演示效果,加载了 8 张 图片。

这里写图片描述

具体的源码如下所示:

ImagesView.h:

#ifndef IMAGES_VIEW_H
#define IMAGES_VIEW_H

#include <QFutureWatcher>
#include <QWidget>

class QLabel;
class QPushButton;
class QVBoxLayout;
class QGridLayout;

class ImagesView : public QWidget
{
    Q_OBJECT

public:
    explicit ImagesView(QWidget *parent = 0);
    ~ImagesView();

private slots:
    void open();  // 打开目录,加载图片
    void showImage(int index);  // 显示图片
    void finished();  // 更新按钮状态

private:
    QPushButton *m_pOpenButton;
    QPushButton *m_pCancelButton;
    QPushButton *m_pPauseButton;
    QVBoxLayout *m_pMainLayout;
    QGridLayout *m_pImagesLayout;
    QList<QLabel *> labels;
    QFutureWatcher<QImage> *m_pWatcher;
};

#endif // IMAGES_VIEW_H
AI 代码解读

下面是实现部分,c_nImageSize 表示的是图片被缩放的大小(宽度:100 px,高度:100px),函数 scale() 则是对图片缩放的具体实现。

ImagesView.cpp

#include <QLabel>
#include <QPushButton>
#include <QProgressBar>
#include <QFileDialog>
#include <QtConcurrent/QtConcurrentMap>
#include <QStandardPaths>
#include <QHBoxLayout>
#include <qmath.h>
#include "ImagesView.h"

const int c_nImageSize = 100;

// 缩放图片
QImage scale(const QString &imageFileName)
{
    QImage image(imageFileName);
    return image.scaled(QSize(c_nImageSize, c_nImageSize), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}

ImagesView::ImagesView(QWidget *parent)
    : QWidget(parent)
{
    setWindowIcon(QIcon(":/Images/logo"));
    setWindowTitle(QStringLiteral("Qt之QFutureWatcher"));
    resize(800, 600);

    // 初始化控件
    m_pWatcher = new QFutureWatcher<QImage>(this);
    m_pOpenButton = new QPushButton(QStringLiteral("打开图片"));
    m_pCancelButton = new QPushButton(QStringLiteral("取消"));
    m_pPauseButton = new QPushButton(QStringLiteral("暂停/恢复"));
    QProgressBar *pProgressBar = new QProgressBar(this);

    m_pCancelButton->setEnabled(false);
    m_pPauseButton->setEnabled(false);

    // 布局
    QHBoxLayout *pButtonLayout = new QHBoxLayout();
    pButtonLayout->addWidget(m_pOpenButton);
    pButtonLayout->addWidget(m_pCancelButton);
    pButtonLayout->addWidget(m_pPauseButton);
    pButtonLayout->addStretch();
    pButtonLayout->setSpacing(10);
    pButtonLayout->setMargin(0);

    m_pImagesLayout = new QGridLayout();

    m_pMainLayout = new QVBoxLayout();
    m_pMainLayout->addLayout(pButtonLayout);
    m_pMainLayout->addWidget(pProgressBar);
    m_pMainLayout->addLayout(m_pImagesLayout);
    m_pMainLayout->addStretch();
    m_pMainLayout->setSpacing(10);
    m_pMainLayout->setContentsMargins(10, 10, 10, 10);
    setLayout(m_pMainLayout);

    // 连接信号槽 - 加载、显示进度、打开、取消等操作
    connect(m_pWatcher, SIGNAL(resultReadyAt(int)), SLOT(showImage(int)));
    connect(m_pWatcher, SIGNAL(progressRangeChanged(int,int)), pProgressBar, SLOT(setRange(int,int)));
    connect(m_pWatcher, SIGNAL(progressValueChanged(int)), pProgressBar, SLOT(setValue(int)));
    connect(m_pWatcher, SIGNAL(finished()), SLOT(finished()));
    connect(m_pOpenButton, SIGNAL(clicked()), SLOT(open()));
    connect(m_pCancelButton, SIGNAL(clicked()), m_pWatcher, SLOT(cancel()));
    connect(m_pPauseButton, SIGNAL(clicked()), m_pWatcher, SLOT(togglePaused()));
}

ImagesView::~ImagesView()
{
    m_pWatcher->cancel();
    m_pWatcher->waitForFinished();
}

// 打开目录,加载图片
void ImagesView::open()
{
    // 如果已经加载图片,取消并进行等待
    if (m_pWatcher->isRunning()) {
        m_pWatcher->cancel();
        m_pWatcher->waitForFinished();
    }

    // 显示一个文件打开对话框
    QStringList files = QFileDialog::getOpenFileNames(this,
                                                      QStringLiteral("选择图片"),
                                                      QStandardPaths::writableLocation(QStandardPaths::PicturesLocation),
                                                      "*.jpg *.png");

    if (files.count() == 0)
        return;

    // 做一个简单的布局
    qDeleteAll(labels);
    labels.clear();

    int dim = qSqrt(qreal(files.count())) + 1;
    for (int i = 0; i < dim; ++i) {
        for (int j = 0; j < dim; ++j) {
            QLabel *pLabel = new QLabel(this);
            pLabel->setFixedSize(c_nImageSize, c_nImageSize);
            m_pImagesLayout->addWidget(pLabel, i, j);
            labels.append(pLabel);
        }
    }

    // 使用 mapped 来为 files 运行线程安全的 scale 函数
    m_pWatcher->setFuture(QtConcurrent::mapped(files, scale));

    m_pOpenButton->setEnabled(false);
    m_pCancelButton->setEnabled(true);
    m_pPauseButton->setEnabled(true);
}

// 显示图片
void ImagesView::showImage(int index)
{
    labels[index]->setPixmap(QPixmap::fromImage(m_pWatcher->resultAt(index)));
}

// 更新按钮状态
void ImagesView::finished()
{
    m_pOpenButton->setEnabled(true);
    m_pCancelButton->setEnabled(false);
    m_pPauseButton->setEnabled(false);
}
AI 代码解读

构造函数中,需要注意的是槽函数,其中 resultReadyAt() 表示 index 对应位置的处理结果已准备就绪,所以连接该信号至槽函数 showImage(),可以显示处理完的图片。

为了显示处理进度,我们构造了一个进度条,当 QFutureWatcher 的 progressRangeChanged() 的信号发射时,进度条的范围会发生改变,而 progressValueChanged() 信号发射时,会更新进度条的值。

如果加载的图片较多时,可以通过点击“取消”按钮,这时会调用 QFutureWatcher 的 cancel() 槽函数来取消计算。“暂停/恢复”则调用 togglePaused() 槽函数,用于切换异步计算的暂停状态,换句话说,如果计算当前已暂停,调用此函数将进行恢复;如果计算正在运行,则会暂停。

当点击“打开”按钮时,会调用槽函数 open(),默认打开图片目录,以便进行图片的选择。然后根据图片创建对应数量的标签 QLabel,用于显示后期缩放的图片。创建完成后,使用 mapped() 进行并行计算,并添加至 QFutureWatcher 中,让其使用信号和槽监视 QFuture。

接下来,就可以直接使用了。

#include <QApplication>
#include "ImagesView.h"

int main(int argc, char *argv[])
{
    QApplication app(argc,argv);

    ImagesView view;
    view.show();

    return app.exec();
}
AI 代码解读

这样,我们就完成了一个图片缩放加载缩放的功能。

更多参考

目录
打赏
0
0
0
0
34
分享
相关文章
|
11月前
|
QT之QFlags详解
QT之QFlags详解
290 0
Qt之QFtp
简述 QFtp 类提供了一个 FTP 协议的客户端实现。 该类提供了一个到 FTP 的直接接口,允许对请求有更多的控制。但是,对于新的应用程序,建议使用 QNetworkAccessManager 和 QNetworkReply,因为这些类拥有一个更简单、还更强大的 API。 简述 QFtp 工作流程 基本使用 连接并登录 FTP 服务器 切换工作目录 列出目
7259 1
【Qt】-学Qt前的准备
【Qt】-学Qt前的准备
Qt资料大全
简述 发福利了、发福利了、发福利了,重要的事情说三遍。。。 为了方便更多Qter了解、学习Qt,现将相关资源进行整理,主要内容包括:Qt官网、编码风格、GitHub &amp; Third-Party、社区论坛、博客、书籍等。 满满的都是干货,独乐乐不如众乐乐。。。 简述 Qt官网 编码风格 GitHub Third-Party 社区论坛 博客 书籍 更多
2971 0
Qt之QTimeLine
简述 QTimeLine 类提供了用于控制动画的时间轴,通常用于通过定期调用一个槽函数来动画一个 GUI 控件。 相信了解动画的人对帧应该不陌生,可以把一个动画想象成由很多张静态画面组成,而每一个画面就是一帧图像。每隔一定时间间隔就显示一帧图像,当该间隔较短时,人眼就感觉不出来了,觉得看到的是连续的影像。 简述 详细说明 状态 方向 曲线形状 详细
2323 0
Qt之QUrl
简述 QUrl 类提供了一个方便的接口使用 URLs。 它可以解析和构造编码和未编码形式的 URLs。QUrl 也支持国际化域名(IDNs)。 简述 详细描述 错误检查 字符转换 URL格式 scheme Authority user info path query fragment 深入使用 相对路径 用户输入 文件名 主机端口 本地文件 百分比编码
6425 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等