Qml中实现多视图,多图像源(QImage / QPixmap)

news2024/9/20 8:02:58

转自: Qml中实现多视图,多图像源(QImage / QPixmap)_engine.addimageprovider-CSDN博客

【写在前面】

       在 Qml 中,实现多视图很容易,无非是多个 Image 而已。

       但是,如果需要动态刷新,则变得困难。

       再或者,来自多个不同的图像源,将更加复杂。

       实际上,这在 Qt ( Widgets ) 中实现却很容易,究其原因,是 Qml 中缺少对 QImage ( 或者说 原始图像 ) 的支持 。

       即便如此,Qt 仍提供了一种解决方法。

       本篇主要内容:

       1、QML 中支持 QImage / QPixmap 。

       2、QML 中实现多视图。

       3、QML 中实现多图像源视图。

【正文开始】

       首先,展示一下效果图。

       多视图的:

多图像源的:

  •  想要在 QML 中实现上面的效果,必须学会在 QML 中使用 QImage / QPixmap 。

       其中,核心的 Class 为 QQuickImageProvider

QQuickImageProvider is used to provide advanced image loading features in QML applications. It allows images in QML to be:

Loaded using QPixmaps rather than actual image files.

Loaded asynchronously in a separate thread.

To specify that an image should be loaded by an image provider, use the "image:" scheme for the URL source of the image, followed by the identifiers of the image provider and the requested image.

翻译:

QQuickImageProvider 用于在 QML 应用程序中提供高级图像加载功能。 它允许 QML 中的图像为:

使用 QPixmaps 而不是实际的图像文件加载。

在单独的线程中异步加载。

要指定图像提供者应加载图像,请对图像的URL源使用“ image:”方案,然后使用图像提供者的标识符和请求的图像。

       根据文档以及示例,很容易明白 QQuickImageProvider 的工作方式:

       1、写一个自己的 QQuickImageProvider。

       2、使用 void QQmlEngine::addImageProvider(const QString &providerId, QQmlImageProviderBase *provider),添加到 QmlEngine 中,并且拥有其所有权。

       3、Qml 中 Image 的 source 前缀为:"image://" 来请求图像。

       4、请求将调用 QQuickImageProvider 中的 requestImage() / requestPixmap() / requestTexture(),藉此返回 C++ 提供的图像 ( QImage / QPixmap / QQuickTextureFactory )。

对于 request*() 函数,需要注意的是:该方法可能被多个线程调用,因此请确保该方法的实现是可重入 ( 即线程安全 ) 的。

  • 现在我们来实现第一个:多视图。

       Qml 部分关键代码如下:

Page {
    id: page1
    width: 860
    height: 660
 
    Connections {
        target: view
        onViewNeedUpdate: {
            /**
              * 1. index为视图索引
              * 2. ###用于分隔
              * 3. Date.now()用于更新
              */
            viewRepeater.itemAt(index).source = "image://MultiView/" + index + "###" + Date.now();
        }
    }
 
    Grid {
        rows: 3
        columns: 3
        anchors.fill: parent
 
        Repeater {
            id: viewRepeater
            model: 9
 
            Image {
                mipmap: true
                width: page1.width / 3
                height: page1.height / 3
 
                Text {
                    anchors.left: parent.left
                    anchors.leftMargin: 12
                    anchors.top: parent.top
                    anchors.topMargin: 12
                    font.bold: true
                    font.pointSize: 30
                    color: "red"
                    text: index
                }
 
                Rectangle {
                    anchors.fill: parent
                    border.width: 2
                    border.color: "yellow"
                    color: "transparent"
                }
            }
        }
    }
}

     其中,viewRepeater.itemAt(index).source = "image://MultiView/" + index + "###" + Date.now() 将调用 requestImage()。

    然后,我们实现自己的 ImageProvider ( 这里是 ViewProvider ):

#ifndef VIEWPROVIDER_H
#define VIEWPROVIDER_H
 
#include <QQuickImageProvider>
 
class ViewProvider : public QQuickImageProvider
{
public:
    ViewProvider();
    void updateView(int index, const QImage &view);
    QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
 
private:
    /**
     * @note 为什么使用 hash 而不是 vector
     *       因为这样可以扩展到更广泛的使用场景
     */
    QHash<int, QImage> m_views;
};
 
#endif // VIEWPROVIDER_H
#include "viewprovider.h"
 
ViewProvider::ViewProvider()
    : QQuickImageProvider(QQuickImageProvider::Image)
{
 
}
 
void ViewProvider::updateView(int index, const QImage &view)
{
    m_views[index] = view;
}
 
QImage ViewProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    //这里可以id.left(1);
    int index = id.left(id.indexOf("###")).toInt();
    QImage view = m_views[index];
 
    if (!view.isNull()) {
        view.scaled(requestedSize);
 
        if (size) *size = requestedSize;
    }
 
    return view;
}

       接着,使用 addImageProvider Qml 引擎中。

       其中 ProviderId 分别为 MultiView ( Qml 中使用 image://MultiView 访问),MultiSource ( Qml 中使用 image://MultiSource 访问):

#include "view.h"
#include "viewprovider.h"
 
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
 
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
 
    QGuiApplication app(argc, argv);
 
    View *view = new View;
 
    QQmlApplicationEngine engine;
    engine.addImageProvider(QLatin1String("MultiView"), view->multiView());
    engine.addImageProvider(QLatin1String("MultiSource"), view->multiSource());
    engine.rootContext()->setContextProperty("view", view);
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
 
    return app.exec();
}

最后,我们只需送入 QImage 并提示 Qml 更新即可:

    //多视图图像生成器
    d->m_generator = new QTimer(this);
    connect(d->m_generator, &QTimer::timeout, this, [this]() {
        static int index = 0;
        QImage image = QGuiApplication::primaryScreen()->grabWindow(0).toImage();
        d->m_multiView->updateView(index, image);
        emit viewNeedUpdate(index);
 
        if (++index == 9) index = 0;
    });
    d->m_generator->start(1000 / 9);

       这里的图像源为桌面截图,间隔 111ms,送给九个视图进行显示。

  • 现在我们来实现第二个:多图像源视图。

       在上面,我们已经成功实现了一个图像源的多视图展示,现在更进一步,提供多个图像源。

       Qml 部分关键代码如下:

Page {
    id: page2
    width: 860
    height: 660
 
    Connections {
        target: view
        onSourceNeedUpdate: {
            /**
              * 1. source为图像源索引
              * 2. ###用于分隔
              * 3. Date.now()用于更新
              */
            sourceRepeater.itemAt(source).source = "image://MultiSource/" + source + "###" + Date.now();
        }
    }
 
    Grid {
        rows: 2
        columns: 2
        anchors.fill: parent
 
        Repeater {
            id: sourceRepeater
            model: 4
 
            Image {
                mipmap: true
                width: page2.width / 2
                height: page2.height / 2
                fillMode: Image.PreserveAspectFit
 
                property bool running: true
 
                Image {
                    width: 80
                    height: 80
                    anchors.centerIn: parent
                    opacity: 0.7
                    mipmap: true
                    source: parent.running ? "" : "qrc:/play.png"
                }
 
                Text {
                    anchors.left: parent.left
                    anchors.leftMargin: 12
                    anchors.top: parent.top
                    anchors.topMargin: 12
                    font.bold: true
                    font.pointSize: 30
                    color: "red"
                    text: index
                }
 
                Rectangle {
                    anchors.fill: parent
                    border.width: 2
                    border.color: "#89f2f5"
                    color: "transparent"
                }
 
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        if (parent.running) {
                            view.pauseSource(index);
                            parent.running = false;
                        } else {
                            view.resumeSource(index);
                            parent.running = true;
                        }
                    }
                }
            }
        }
    }
}

       这里基本类似,只是多了暂停 / 继续而已。

       C++ 部分关键代码:

    /**
     * @note 多图像源
     * @source[0-4] gif[0-4]
     */
    for (int i = 0;  i < 4; i++) {
        d->m_sources[i] =  new QMovie(":/" + QString::number(i) + ".gif", "GIF", this);
        qDebug() << d->m_sources[i]->fileName() << d->m_sources[i]->isValid();
        connect(d->m_sources[i], &QMovie::frameChanged, this, [i, this](int) {
            d->m_multiSource->updateView(i, d->m_sources[i]->currentImage());
            emit sourceNeedUpdate(i);
        });
    }

       如你所见,四个图像源来自四张不同的 GIF 图像,之所以用这种形式,是因为可以让人联想到其他类似的场景:

       1、多个监视器( 多个摄像头 )。

       2、多个图像源( 多个视频源 )。 

       而对于这些场景,我觉得是相当有用的。

【结语】

       实际上,在 Qml 使用 QImage 确实有些麻烦。

       当然,对我来说,因为用得多了,反倒是挺习惯的。

       并且也渐渐明白了,Qml 只做前端显示,复杂的工作都由后端的 C++ 来完成。

       然后一点题外话要说,注意:

Image Caching:

Images returned by a QQuickImageProvider are automatically cached, similar to any image loaded by the QML engine. When an image with a "image://" prefix is loaded from cache, requestImage() and requestPixmap() will not be called for the relevant image provider. If an image should always be fetched from the image provider, and should not be cached at all, set the cache property to false for the relevant Image, BorderImage or AnimatedImage object.

翻译:图像缓存

由 QQuickImageProvider 返回的图像将自动缓存,类似于 QML 引擎加载的任何图像。 当从缓存中加载带有 "image://" 前缀的图像时,相关图像提供者将不会调用 requestImage() 和 requestPixmap() 。 如果应该始终从图像提供者获取图像,并且根本不应该对其进行缓存,则将相关 Image,BorderImage 或 AnimatedImage 对象的 cache 属性设置为 false。

       然而,将 cache 设置为 false 并没有卵用,仍然需要使用 Date.now() 来请求一个不同的图像,才能造成刷新的效果( 也许这是一个 Bug),但不管怎么说,这个坑必须小心。

       最后,附上项目链接(多多star呀..⭐_⭐):

       CSDN的:Qml中实现多视图,多图像源(QImage/QPixmap)_QPixmap-C++文档类资源-CSDN下载

       Github的:GitHub - mengps/QmlExamples: Qt Quick/Qml 示例,说不定有用呢~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2075699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Icepak与RHSC-ET耦合计算Die温度场

目录 1 背景介绍 2 工作流程 2.1 概述 2.2 几何处理 2.3 电热耦合计算温度场 2.4 输出HTC 2.5 RHSC-ET读入HTC 3 求解及总结 以下内容截取自该篇资料 几何处理 • 通过stp文件导入系统散热结构 • 修复几何模型&#xff0c;液冷抽出流体 • 模型简化 电热耦合计算…

Android高级UI --- canvas

前言 我们先来聊聊&#xff0c;在我们生活中如何绘制一张如下的图。 我们需要两样东西来绘制&#xff1a; 一张纸&#xff08;Android 中的 canvas&#xff09;&#xff1a;用来承载我们绘制的内容。一支笔&#xff08;Android 中的 paint&#xff09;&#xff1a;负责绘制内…

SpringBoot3核心特性-Web开发

目录 传送门前言一、WebMvcAutoConfiguration原理1、生效条件2、效果3、WebMvcConfigurer接口4、静态资源规则源码5、EnableWebMvcConfiguration 源码6、为什么容器中放一个WebMvcConfigurer就能配置底层行为7、WebMvcConfigurationSupport 二、Web场景1、自动配置2、默认效果 …

自动化构建工具Gulp

第三方模块-Gulp 解释 基于node平台开发的前端构建工具 将机械化操作编写成任务&#xff0c;由一条命令来触发执行&#xff0c;提高开发效率 主要能做什么 项目上线&#xff1a;html、css、js文件的压缩合并语法转换&#xff1a;es6、less等语言的转化公共文件抽离修改文件…

替代液压比例放大器首选

比例阀放大器的选用应考虑诸多因素&#xff0c;如系统需求、放大器的兼容性、调节性、附加功能、安全特性、供应商支持和环境适应性等。 系统性能要求明确 压力与流量: 根据液压系统所需的压力和流量来确定放大器的性能指标&#xff0c;以确保比例阀能得到充分的功率支持。 …

2024/8/26 英语每日一段

Apple and Google have had nearly unchecked power over mobile apps in ways that raise prices for some of what you buy, block you from trying clever ideas, push app makers to do scuzzy things to make money, and impose Apple’s and Google’s wishes on all us.…

如何用Java SpringBoot+Vue开发高效OA办公管理系统

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

三品船舶PLM解决方案详情 三品PLM软件在船舶制造行业应用优势

自2024年起&#xff0c;船舶行业PLM&#xff08;产品全生命周期管理&#xff09;技术步入关键发展阶段。国产化工业软件领域积极倡导生态合作&#xff0c;推广统一技术底座下的合作开发模式&#xff0c;整合国内外成熟的工业软件技术与应用资源&#xff0c;旨在全面提升国内船舶…

【Bigtop】利用Bigtop3.2.0编译大数据组件RPM包

利用Bigtop3.2.0编译大数据组件RPM包 前言正文Mvn本地目录的修改FlinkKafkagrgit版本手动准备gradle的文件 前言 原文参考&#xff1a;Bigtop 从0开始 参考了上述的博文自己尝试了编译组件&#xff0c;过程还是遇到很多问题&#xff0c;一一记录&#xff0c;方便后人。 Bigt…

【方案】智慧排水系统解决方案(doc原件)

一、项目建设目标 二、项目主要内容 三、项目建设方案 1.GIS管理子系统 &#xff08;1&#xff09; 数据管理和访问 &#xff08;2&#xff09; 地图操作功能 &#xff08;3&#xff09; 地图查询定位功能 &#xff08;4&#xff09; 其他功能 2.工程管理子系统 &#xff08;1&…

免费分享!算法备案流程以及所需资料

免费分享&#xff01;算法备案流程以及所需资料 在国内&#xff0c;随着《生成式人工智能服务管理暂行办法》的出台&#xff0c;这一规定明确指出&#xff0c;任何面向中国公众提供具备舆论影响力或社会动员潜力的生成式AI服务&#xff0c;都必须经过严格的算法备案程序。 这就…

有关于算法备案的五大误区

有关于算法备案的五大误区 在这个数据为王的时代&#xff0c;算法已然成为推动社会前进的隐形巨轮。从搜索框中的每一次点击&#xff0c;到购物车里的每一件商品推荐&#xff0c;再到朋友圈里刷屏的动态&#xff0c;算法的身影无处不在&#xff0c;悄无声息地编织着我们的数字生…

云HIS系统,利用云计算平台的技术优势,建立统一的健康档案和电子存储平台,实现医疗数据共享与交换

云HIS系统源码&#xff0c;医院信息管理系统源码&#xff0c;医疗云HIS源码 基于云计算技术的B/S架构的HIS系统&#xff0c;为医疗机构提供标准化的、信息化的、可共享的医疗信息管理系统&#xff0c;实现医患事务管理和临床诊疗管理等标准医疗管理信息系统的功能。系统利用云计…

项目经理都在用的五款项目管理工具(建议收藏)

在项目管理中&#xff0c;选择合适的工具对于确保项目成功至关重要。 以下是几款备受项目经理青睐的项目管理软件&#xff1a; 1、进度猫 进度猫是一款基于云端的项目管理工具&#xff0c;以其轻量级、直观和易操作的特点受到项目经理的青睐。它提供了丰富的功能和灵活的操…

如何安装和高级 AMP for WP

当 WordPress 是支持 AMP 的 WEB 站点时&#xff0c;主要通过两个插件支持 AMP。 一个是AMP插件。 这个插件也参与谷歌的开发&#xff0c;并被确认为AMP项目的官方插件。 我最初也安装了这个AMP插件&#xff0c;但我不知道是否能够共存的常规网站和AMP兼容网站&#xff0c;很难…

这只猴子一夜赚了15亿?

通过《黑神话》思考低代码平台的发展 《黑神话》的设计分析 《黑神话》作为一款大型3A游戏&#xff0c;其优化工作主要聚焦于提升游戏性能、增强画面表现以及提升玩家体验。这包括但不限于以下几个方面&#xff1a; 技术突破&#xff1a;游戏采用了前沿的技术手段&#xff0…

AppInventor2 文本输入框(TextBox)已支持文本变更事件,非常便于实时处理输入的内容

自 v2.70开始&#xff0c;文本输入框加入了文本变更事件&#xff1a; 效果如下&#xff1a; 文本事件.gif (99.17 KB, 下载次数: 3) 下载附件 昨天 19:57 上传 同理&#xff0c;密码输入框组件也是一样的。 原文&#xff1a;AppInventor2 文本输入框&#xff08;TextBox&a…

用Python实现9大回归算法详解——08. 随机森林回归算法

1. 随机森林回归的基本概念 随机森林回归&#xff08;Random Forest Regression&#xff09;是一种集成学习方法&#xff0c;基于多棵决策树的组合来进行预测。它通过引入随机性来构建多棵独立的决策树&#xff0c;并将这些树的预测结果进行平均&#xff0c;从而提升模型的泛化…

streeapptest 工具编译看 + 测试rk3568

首先来了解一下 stressappteset 网上的资料 压力测试不就是 内存的接口测试吗&#xff1f; 网上找了些资料&#xff0c;基本没有这个工具对于 磁盘网络的测试。 我的理解&#xff0c;压力测试应该指的就是 CPU内存的测试吧。 然后是 关于这个 软件的编译。 首先是下载 git c…

避雷!Springer、Cell等出版社旗下17本SCI/SSCI被剔除,含3本on hold期刊!

2024年8月19日&#xff0c;科睿唯安本年度第八次更新Web of Science核心期刊目录。 图片来源&#xff1a;科睿唯安 与上次更新&#xff08;2024年7月&#xff09;相比&#xff0c;此次更新后的SCIE、SSCI期刊目录共17本期刊发生变动&#xff0c;详情如下&#xff1a; 图片来源…