专栏首页跟Qt君学编程QML动态显示组件(支持在线编辑动态刷新)

QML动态显示组件(支持在线编辑动态刷新)

先上视频效果:

QML动态组件显示器主要用于方便界面开发,在线编辑保存后自动刷新组件界面,并支持拖拽文件显示的方式。

QML部分代码:

import QtQuick 2.6
import MonitorAndControlFile 1.0
import QtQuick.Window 2.0

Window {
    id: root

    property variant qmlObjects: []

    visible: true
    width: 320*1.5
    height: 240*1.5
    title: qsTr("QML组件动态显示器v0.3")

    Column {
        Item {
            width: root.width; height: root.height - background.height
            Column {
                anchors.centerIn: parent
                spacing: 10

                Text {
                    anchors.horizontalCenter: parent.horizontalCenter
                    font.pixelSize: 24
                    color: "gray"
                    text: "将QML文件拖到这里显示"
                }

                Text {
                    anchors.horizontalCenter: parent.horizontalCenter
                    font.pixelSize: 24
                    color: "gray"
                    text: "修改QML文件实时动态刷新"
                }
            }
        }

        Image {
            id: background
            anchors.horizontalCenter: parent.horizontalCenter
            width: root.width*0.8; height: width*800/2800
            source: "qrc:/Other/xiaoxuesheng.jpg"
        }
    }

    MonitorAndControlFile {
        id: monitorAndControlFile
        onStatusChanged: load(url)
    }

    DropArea {
        anchors.fill: parent
        onDropped: monitorAndControlFile.url = (drop.text.replace(/[\r\n]/g,""))
    }

    function load(url) {
        monitorAndControlFile.clear()

        for (var i = 0; i < qmlObjects.length; i++) {
            var obj = qmlObjects[i]
            /* 开启这两个只能显示一个组件 */
//            obj.visible = false 
//            console.log(obj)
        }

        console.log("Load: ", url)

        try {
            var component = Qt.createComponent(url);
        } catch(err) {
            console.log('Error on line ' + err.qmlErrors[0].lineNumber + '\n' + err.qmlErrors[0].message);
        }

        if (component.status == Component.Error) {
            console.log("Error loading component:", component.errorString());
            return null;
        }

        if (component.status == Component.Ready) {
            var object = component.createObject(root);
            object.visible = true
            qmlObjects.push(object)
        }
    }
}

C++部分代码:

#include "MonitorAndControlFile.h"

#include <QFileInfo>
#include <QDebug>

void MonitorAndControlFile::clear()
{
    m_engine->trimComponentCache();
    m_engine->clearComponentCache();
}

MonitorAndControlFile::MonitorAndControlFile(QObject *parent) : QObject(parent)
{
    connect(&m_fileWatch, SIGNAL(fileChanged(QString)), this, SLOT(onFileChanged(QString)));
    m_engine = qmlEngine();
}

MonitorAndControlFile::~MonitorAndControlFile()
{
}

QString MonitorAndControlFile::url()
{
    return m_url;
}

void MonitorAndControlFile::setUrl(QString url)
{
    QString file = url;
#ifdef Q_OS_WIN
    QFileInfo fileInfo(file.remove("file:///"));
#endif

#ifdef Q_OS_UNIX
    QFileInfo fileInfo(file.remove("file://"));
#endif

    if (fileInfo.isFile()) {
        m_fileWatch.addPath(file);
        if (!m_monitorFiles.contains(file))
            m_monitorFiles.append(file);

        m_url = url;
        emit statusChanged();
    }
}

void MonitorAndControlFile::onFileChanged(QString file)
{
    foreach(QString file, m_monitorFiles) {
        m_fileWatch.addPath(file);
    }
    qDebug()<<"Watch file: "<<m_fileWatch.files();
    emit statusChanged();
}

实现原理:

1. QML端实现方式主要是拖拽方式的实现与QML组件的动态加载显示;

拖拽实现获取QML组件:

DropArea { 
        anchors.fill: parent
        onDropped: monitorAndControlFile.url = (drop.text.replace(/[\r\n]/g,""))
    }

QML动态加载:

try {
            var component = Qt.createComponent(url);
        } catch(err) {
            console.log('Error on line ' + err.qmlErrors[0].lineNumber + '\n' + err.qmlErrors[0].message);
        }

2. C++端主要实现的是监控文件的变化,进而动态加载QML组件;

clear函数主要用于更新组件需要清除上一个组件的资源,不然不能更新到组件刷新。

void MonitorAndControlFile::clear()
{
    m_engine->trimComponentCache();
    m_engine->clearComponentCache();
}

MonitorAndControlFile类构造函数用于绑定文件监控

MonitorAndControlFile::MonitorAndControlFile(QObject *parent) : QObject(parent)
{
    connect(&m_fileWatch, SIGNAL(fileChanged(QString)), this, SLOT(onFileChanged(QString)));
    m_engine = qmlEngine();
}

3. MonitorAndControlFile类qmlRegisterType注册到QML中通过import导入使用;

qmlRegisterType<MonitorAndControlFile>("MonitorAndControlFile", 1, 0, "MonitorAndControlFile");
import MonitorAndControlFile 1.0

程序的一些小细节:

(1) 由于QML获取到的文件路径有可能附带换行符导致文件不能识别,所以需要移除多余的换行符;

drop.text.replace(/[\r\n]/g,"")

(2) 由于操作系统不一样导致到Windows系统与Linux系统的文件读取方式也不一样。这里用到了系统宏判断移除多余的前缀。

Windows系统获取文件方式:
"file:///C:/Users/Strong/Documents/workspace/DisplayQtComponent/Other/Text-1.qml"
Linux系统获取文件方式: 
"file:///Users/Strong/Documents/workspace/DisplayQtComponent/Other/Text-1.qml"
#ifdef Q_OS_WIN
    QFileInfo fileInfo(file.remove("file:///"));
#endif

#ifdef Q_OS_UNIX
    QFileInfo fileInfo(file.remove("file://"));
#endif

代码地址(不定时更新):

https://github.com/aeagean/DisplayQtComponent

本文分享自微信公众号 - Qt君(qtjuna)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-11-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Shiro教程一Shiro之helloworld

    凯哥Java
  • 关于在Spring 中方法内部调用自身方法事务 REQUIRE_NEW 不生效的解释

    这个是Spring 对拦截的实现有关。Spring 拦截实现的方法是动态生成一个代理类。正常使用 @Autowired 注解注入的实际上就是这个代理类。

    Dylan Liu
  • Freemark学习(三):流程控制语句&list&map获取

    在前两节学习中我们知道了freemark的hello Word 以及freemark的部分数据类型。

    凯哥Java
  • Shiro学习系列教程三:集成web

    本节主要内容:   1:shiro怎么集成到web开发中。  涉及到的网站:  shiro官网:http://shiro.apache.org/web.html...

    凯哥Java
  • 单元测试框架系列教程9-测试方法、类以及组的概念

    本篇来介绍Test Methods, Test classes ,Test groups的基本概念。了解这三个基本概念,有助于我们学习其他的功能。前面介绍了@T...

    凯哥Java
  • 不要使用 YYYY ,使用 yyyy 来获取年份

    使用format 出来的日期的正确的,不要欢喜的太早,parse 给出的结果就完全让人摸不着头脑。

    Dylan Liu
  • Shiro学习系列教程二:从数据库中获取认证信息

    本讲主要内容: 1:shiro框架流程了解  2:用户名密码从数据库中读取后进行验证(在实际工作中一般使用这种)  第一节:shiro框架流程了解 首先,...

    凯哥Java
  • 记录一次spring boot和dubbo整合使用的走的坑

    在controller调用service层的时候,之前使用spring 框架的,习惯性的controller注入service层使用注解是:

    凯哥Java
  • spring 整合 redis,以及spring的RedisTemplate如何使用

    需要的jar包 spring-data-redis-1.6.2.RELEASE.jar jedis-2.7.2.jar(依赖 commons-pool2-2...

    凯哥Java
  • Selenium+TestNG实战-2 第一个Selenium脚本之登录

    前一篇,我们准备了好wordPress本地环境和eclipse编写脚本环境,这篇,我们新建一个Java main方法,不管什么技巧,框架,什么数据分离,完全是根...

    凯哥Java

扫码关注云+社区

领取腾讯云代金券