第四章:QML中呼叫C++互動

俊俊~發表於2020-10-25

 

1、QML中呼叫C++互動方法

Qt整合了QML引擎和Qt元物件系統,使得QML很容易從C++中得到擴充套件,在一定的條件下,QML就可以訪問QObject派生類的成員,例如訊號、槽函式、列舉型別、屬性、成員函式等。

 

QML訪問C++需要將c++類擴充套件到qml中,有兩個方法:

1、在Qt元物件系統中註冊C++類到qml中

2、將物件或資料暴露給 QML

相關函式:

setContextProperty()//將物件或資料暴露給 QML
qmlRegisterType()//註冊C++類到qml中
qmlRegisterSingletonType()//註冊C++單例到qml中

 

實現可以被QML訪問的C++類的屬性和方法 必須滿足兩個條件:

1、派生自QObject類或QObject類的子類

2、使用Q_OBJECT巨集

 

訪問屬性和方法:

1、訊號與槽 可以直接訪問

2、列舉型別 使用Q_ENUMS()巨集

3、屬性 使用Q_PROPERTY()巨集

4、方法 使用Q_INVOKABLE()巨集

 

2、Q_PROPERTY巨集

作用:

用來定義可通過元物件系統訪問的屬性,通過它定義的屬性,可以在 QML 中訪問、修改,也可以在屬性變化時發射特定的訊號。該巨集是qt特有的,必須繼承於QObject類。

寫法:

Q_PROPERTY(type name   # 屬性
   READ getFunction     # 讀取屬性值,必須返回屬性的型別的值或指標或引用
   [WRITE setFunction]   # 設定屬性值,返回空並且至少具有一個引數
   [RESET resetFunction]     # 設定屬性的值到預設值
   [NOTIFY notifySignal]     # 屬性的值發生改變時發出訊號
   [DESIGNABLE bool]        # 此屬性是否在介面設計器的屬性編輯器中出現
   [SCRIPTABLE bool]        # 屬性是否可以被一個指令碼引擎操作
   [STORED bool]            # 屬性是否被認為是獨立存在還是依賴於其它的值而存在
   [USER bool]              # 屬性是否被設計為面向使用者的或使用者可修改的類屬性
   [CONSTANT]               # 屬性的值是不變的
   [FINAL])                 # 屬性不能被派生類所重寫

訊號命名:

將 NOTIFY 訊號命名為 <property>Changed 的形式,其中 <property> 是屬性的名稱。由 QML 引擎生成的關聯的屬性更改訊號處理程式將始終採用on<Property>Changed 的形式,而無需關心相關 C++ 訊號的名稱,因此建議訊號名稱遵循此約定,以避免任何混淆。

示例:

Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QColor barColor READ getBarColor WRITE setBarColor)

 

3、Q_INVOKABLE巨集

作用:被修飾的成員函式能夠被元物件系統所喚起

QML 可以訪問 QObject 派生類的函式,但是函式需要滿足以下條件之一:

1、使用 Q_INVOKABLE() 巨集標記的 public 函式

2、public 槽函式

示例:

Q_INVOKABLE void qDebug_Info(int type, QString strInfo);

 

qmlRegisterType

作用:將C++實現的類在QML中呼叫的,連線C++和QML的一個工具

寫法:

int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName)

示例:

main.cpp

#include <QtQml>
qmlRegisterType<Boy>("People", 1,0, "Boy");
qmlRegisterType<Girl>("People", 1,0, "Girl");

xxx.qml

import People 1.0
Boy{
    id:boy
    ...
}
Girl{
    id:girl
    ...
}

 

4、setContextProperty

作用:將物件或資料暴露給 QML,一般預設就是全域性單例

示例:QML中使用C++日誌記錄模組

qmllog4qml.h

#include <QObject>
class QmlLog4Qml : public QObject
{
    Q_OBJECT
public:
    QmlLog4Qml();
    Q_INVOKABLE void qDebug_Info(int type, QString strInfo);
};

qmllog4qml.h.cpp

#include "qmllog4qml.h"
#include <QMutex>
#include <QFile>
#include <QDateTime>
#include <QTextStream>
void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    static QMutex mutex;
    mutex.lock();
    QString text;
    switch(type)
    {
    case QtDebugMsg:
        text = QString("Debug:");
        break;
    case QtWarningMsg:
        text = QString("Warning:");
        break;
    case QtCriticalMsg:
        text = QString("Critical:");
        break;
    case QtFatalMsg:
        text = QString("Fatal:");
    }
    QString message = "";
    if (context.file != nullptr)
    {
        QString context_info = QString("File:(%1) Line:(%2)").arg(QString(context.file)).arg(context.line);
        QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");
        QString current_date = QString("(%1)").arg(current_date_time);
        message = QString("%1 %2 %3 %4").arg(current_date).arg(text).arg(context_info).arg(msg);
    }
    else
    {
        message = msg;
    }
    QFile file("log.txt");
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream text_stream(&file);
    text_stream << message << "\r\n";
    file.flush();
    file.close();
    mutex.unlock();
}
QmlLog4Qml::QmlLog4Qml()
{
    qInstallMessageHandler(outputMessage);
}

void QmlLog4Qml::qDebug_Info(int type, QString strInfo)
{
    QMessageLogContext context;
    context.file = nullptr;
    outputMessage((QtMsgType)type, context, strInfo);
}

 

main.cpp

設定上下文屬性:setContextProperty() 匯出屬性,就可以在 QML 中使用了

#include "qmllog4qml.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    QmlLog4Qml log4Qml;
    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("log4Qml", &log4Qml);
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();
}

QML: 不需要 import 語句,可以直接呼叫 log4Qml.qDebug_Info()

...
Page1Form {
    Keys.enabled: true
    Keys.onEscapePressed: {
        Qt.quit()
    }
    searchbutton.onClicked: {
        log4Qml.qDebug_Info(0, "Qml寫日誌");   //呼叫C++介面
        console.log("查詢內容:" + searchTextField.text);
    }
    ...
}

 

相關文章