找回密码
 立即注册
Qt开源社区 门户 查看内容

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

2019-4-12 05:40| 发布者: admin| 查看: 865| 评论: 0

摘要: 先上视频效果:QML动态组件显示器主要用于方便界面开发,在线编辑保存后自动刷新组件界面,并支持拖拽文件显示的方式。QML部分代码:importQtQuick2.6importMonitorAndControlFile1.0importQtQuick.Window2.0Window{ ...
先上视频效果:



    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
----------------------------------------------------------------------------------------------------------------------
我们尊重原创,也注重分享,文章来源于微信公众号:你才小学生,建议关注公众号查看原文。如若侵权请联系qter@qter.org。
----------------------------------------------------------------------------------------------------------------------

鲜花

握手

雷人

路过

鸡蛋

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了