# 简介
通过c++端侦听qml文件实时刷新界面而无须重新运行应用程序。
- 当前在Mac OSX 系统上测试效果比较好,在Windows上效果不理想,有时候会出现多个窗口。
- PS: 当前代码直接在github编辑器上编辑的,尚未在本地IDE上编辑,可能会有个别地方编辑有误,有空再补充。
# 运行效果
# 代码
- QmlListener.h
#ifndef QMLLISTENER_H
#define QMLLISTENER_H
#include <QObject>
class QQuickView;
class QQmlApplicationEngine;
class QmlListenerPrivate;
class QmlListener : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(QmlListener)
Q_DECLARE_PRIVATE(QmlListener)
QScopedPointer<QmlListenerPrivate> const d_ptr;
public:
explicit QmlListener(const QString &mainQml = QString(), QObject *parent = nullptr);
~QmlListener();
void setIndexQml(const QString &qmlFile);
void listen(QQuickView *view);
void listen(QQmlApplicationEngine *engine);
void addPaths(const QStringList &paths);
void addPath(const QString &path);
signals:
public slots:
void reload(const QString &file);
}
#endif // QMLLISTENER_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- QmlListener.cpp
#include "QmlListener.h"
#include <QFileSystemWatcher>
#include <QQmlApplicationEngine>
#include <QQmlEngine>
#include <QQuickView>
#include <QQmlContext>
#include <QQmlComponent>
class QmlListenerPrivate
{
Q_DECLARE_PUBLIC(QmlListener)
QmlListener *q_ptr;
public:
QmlListenerPrivate(QmlListener *parent);
void watching();
QQuickView *view;
QQmlApplicationEngine *engine;
QFileSystemWatcher *watcher;
QList<QObject *> qmlObjects;
QString mainQml;
}
QmlListenerPrivate::QmlListenerPrivate(QmlListener *parent)
: q_ptr(parent)
, watcher(new QFileSystemWatcher())
{
}
QmlListenerPrivate::watching()
{
Q_Q(QmlListener);
if(!engine && !view)
return ;
const QString basePath = engine ? engine->baseUrl().toString() : view->engine()->baseUrl().toString();
watcher->addPath(basePath);
watcher->addPath(mainQml);
QObject::connect(watcher, &QFileSystemWatcher::fileChanged, q, &QmlListener::reload);
}
QmlListener::QmlListener(const QString mainQml, QObject *parent)
: QObject(parent)
, d_ptr(new QmlListenerPrivate(this))
{
Q_D(QmlListener);
d->mainQml = mainQml;
}
QmlListener::~QmlListener()
{
}
void QmlListener::setIndexQml(const QString &qmlFile)
{
Q_D(QmlListener);
if(qmlFile == d->mainQml)
return;
d->mainQml = qmlFile;
}
void QmlListener::listen(QQuickView *view)
{
Q_D(QmlListener);
d->view = view;
d->watching();
}
void QmlListener::listen(QQmlApplicationEngine *engine)
{
Q_D(QmlListener);
d->engine = engine;
d->watching();
}
void QmlListener::addPaths(const QStringList &paths)
{
Q_D(QmlListener);
d->watcher->addPaths(paths);
}
void QmlListener::addPath(const QString &path)
{
Q_D(QmlListener);
d->watcher->addPath(path);
}
void QmlListener::reload(const QString &file)
{
Q_D(QmlListener);
if(d->view)
{
d->view->setSource(QUrl());
d->view->engine()->clearComponentCache();
d->view->setSource(QUrl(d->mainQml));
}
else if(d->engine)
{
foreach(QObject *obj, d->engine->rootObjects())
{
if(d->qmlObjects.contains(obj))
continue;
d->qmlObjects.append(obj);
d->engine->setObjectOwnership(obj, QQmlApplicationEngine::CppOwnership);
obj->deleteLater();
}
d->engine->clearComponentCache();
d->engine->load(d->mainQml);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 使用
- main.cpp
#include "QmlListener.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QDir>
#include <QDirIterator>
static const QString UI_PATH = "path/to/your/project/qml";
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
#ifdef QT_DEBUG
// scan all qml files
QDir dir(UI_PATH);
dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
dir.setSorting(QDir::Name);
QStringList files;
QDirIterator it(dir, QDirIterator::Subdirectories);
while (it.hasNext())
{
it.next();
QFileInfo info = it.fileInfo();
if(info.isFile())
{
files << info.filePath();
}
}
QmlListener listtener;
listtener.setIndexQml(UI_PATH + "/main.qml");
listtener.addPaths(files);
listtener.listen(&engine);
#endif
return app.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45