先上视频效果:
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