QML UI 与逻辑分开
前言
大多數(shù)開發(fā)者都希望創(chuàng)建一個可維護(hù)的應(yīng)用程序,要達(dá)到該目的的方法之一就是將用戶界面與業(yè)務(wù)邏輯分開,應(yīng)用程序的 UI 應(yīng)該用 QML 編寫的幾個原因如下:
聲明性語言非常適合定義 UI
QML 代碼編寫很簡單,因?yàn)樗?C++更簡潔,并且不是強(qiáng)類型的。這也是使他成為原型的優(yōu)秀語言。
JavaScript 可以很容易地在 QML 中用于響應(yīng)事件。
作為一種強(qiáng)類型語言,C++最適合做應(yīng)用程序的邏輯,通常,此類代碼執(zhí)行復(fù)雜計(jì)算或數(shù)據(jù)處理等任務(wù),這些任務(wù)在 C++中比 QML 中更快。
Qt 提供了各種在應(yīng)用程序中集成 QML 和 C++的方法,前面的文章也有介紹到。典型的用例就會在用戶界面中顯示數(shù)據(jù)列表,如果數(shù)據(jù)集是靜態(tài)的,則用 QML 編寫的模型就足夠用了。
看以下示例,QML 編寫的模型示例:
將 C++用于大型或經(jīng)常修改的動態(tài)數(shù)據(jù)集。
與 C++中的 QML 交互
雖然 Qt 允許從 C++中操作 QML,但是不建議這樣做,來看一個簡化的例子。
從 QML 中提取引用
假設(shè)正在為設(shè)置頁面編寫 UI:
import QtQuick 2.12 import QtQuick.Controls 2.12Page {Button {text: qsTr("Restore default settings")} }我們希望按鈕在單擊時使用 C++執(zhí)行某些操作,我們知道 QML 中的對象可以像在 C++中一樣發(fā)出變化信號,因此先給按鈕定義一個 objectName,以便可以再 C++中找到它:
Button {objectName: "restoreDefaultsButton"text: qsTr("Restore default settings") }然后,在C ++中,我們找到該對象并連接到其變化信號:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QSettings>class Backend : public QObject {Q_OBJECTpublic:Backend() {}public slots:void restoreDefaults() {settings.setValue("loadLastProject", QVariant(false));}private:QSettings settings; };int main(int argc, char *argv[]) {QGuiApplication app(argc, argv);QQmlApplicationEngine engine;engine.load(QUrl(QStringLiteral("qrc:/main.qml")));if (engine.rootObjects().isEmpty())return -1;Backend backend;QObject *rootObject = engine.rootObjects().first();QObject *restoreDefaultsButton = rootObject->findChild<QObject*>("restoreDefaultsButton");QObject::connect(restoreDefaultsButton, SIGNAL(clicked()),&backend, SLOT(restoreDefaults()));return app.exec(); }#include "main.moc"通過這種方法,對象的引用從QML中“拉出”。這里是C ++邏輯層依賴于QML表示層。如果我們以這樣的方式重構(gòu)QML,使得objectName更改或其他一些更改破壞了C ++找到QML對象的能力,那么我們的工作流程變得更加復(fù)雜和繁瑣。
在 QML 中調(diào)用 C++邏輯
重構(gòu) QML 比重構(gòu) C++容易得多,因此為了維護(hù)更方便,我們應(yīng)該盡可能保持 C++類型不去調(diào)用 QML,然后通過將對 C++的類型的引用注冊到 QML 中來調(diào)用。
int main(int argc, char *argv[]) {QGuiApplication app(argc, argv);Backend backend;QQmlApplicationEngine engine;engine.rootContext()->setContextProperty("backend", &backend);engine.load(QUrl(QStringLiteral("qrc:/main.qml")));if (engine.rootObjects().isEmpty())return -1;return app.exec(); }然后直接在 QML 中進(jìn)行調(diào)用:
import QtQuick 2.12 import QtQuick.Controls 2.12Page {Button {text: qsTr("Restore default settings")onClicked: backend.restoreDefaults()} }這種方式,如果將來需要重構(gòu) QML,C++將保持不變。
在上面示例中,我們根據(jù)上下文設(shè)置一個 context 屬性,以將 C++對象公開給 QML 使用,這意味著屬性可提供引擎加載的每個組件使用。對于必須在加載 QML 時必須可用且不能在 QML 中實(shí)例化的對象,上下文屬性非常有用。
有關(guān) C++類型公開給 QML 中使用的方法,之前的文章有介紹過,在這里。
總結(jié)
以上是生活随笔為你收集整理的QML UI 与逻辑分开的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: QML类型系统
- 下一篇: QML 性能优化建议(一)