溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

將C++?類型屬性暴露給QML的示例分析

發(fā)布時間:2021-12-15 17:29:22 來源:億速云 閱讀:104 作者:柒染 欄目:開發(fā)技術(shù)

這期內(nèi)容當中小編將會給大家?guī)碛嘘P(guān)將C++ 類型屬性暴露給QML的示例分析,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

    一、數(shù)據(jù)類型處理和所有權(quán)

    任何從 C++ 傳輸?shù)?QML 的數(shù)據(jù),無論是作為屬性值、方法參數(shù)或返回值,還是信號參數(shù)值,都必須是 QML 引擎支持的類型。

    默認情況下,引擎支持許多 Qt C++ 類型,并且可以在從 QML 使用時自動適當?shù)剞D(zhuǎn)換它們。

    1.1、暴露屬性

    可以使用 Q_PROPERTY() 宏為任何 QObject 派生類指定屬性。

    例如,下面是一個具有作者屬性的 Message 類。 正如 Q_PROPERTY 宏調(diào)用所指定的,這個屬性可以通過 author() 方法讀取,通過 setAuthor() 方法寫入:

    注意:不要使用 typedef 或 using 指定 Q_PROPERTY 類型,因為它們會混淆 moc。 這可能會使某些類型比較失敗。

    錯誤用法:

    using FooEnum = Foo::Enum;
     
    class Bar : public QObject 
    {
        Q_OBJECT
        Q_PROPERTY(FooEnum enum READ enum WRITE setEnum NOTIFY enumChanged)
    };

    正確用法:

    class Bar : public QObject 
    {
        Q_OBJECT
        Q_PROPERTY(Foo::Enum enum READ enum WRITE setEnum NOTIFY enumChanged)
    };

    暴露屬性實例:

    class Message : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
    public:
        void setAuthor(const QString &a) 
        {
            if (a != m_author) 
            {
                m_author = a;
                emit authorChanged();
            }
        }
        QString author() const 
        {
            return m_author;
        }
    signals:
        void authorChanged();
    private:
        QString m_author;
    };

    如果在從 C++ 加載名為 MyItem.qml 的文件時將此類的實例設(shè)置為上下文屬性:

    int main(int argc, char *argv[]) 
    {
        QGuiApplication app(argc, argv);
     
        QQuickView view;
        Message msg;
        view.engine()->rootContext()->setContextProperty("msg", &msg);
        view.setSource(QUrl::fromLocalFile("MyItem.qml"));
        view.show();
     
        return app.exec();
    }
    然

    可以從 MyItem.qml 中讀取 author 屬性:

    // MyItem.qml
    import QtQuick 2.0
     
    Text 
    {
        width: 100; height: 100
        text: msg.author    // 調(diào)用 Message::author() 來獲取這個值
     
        Component.onCompleted: 
        {
            msg.author = "Jonah"  // 調(diào)用 Message::setAuthor()    
        }
    }

    為了實現(xiàn)C++與 QML 的最大互操作性,任何可寫的屬性都應(yīng)該有一個關(guān)聯(lián)的 NOTIFY 信號,該信號在屬性值更改時發(fā)出。這允許屬性與屬性綁定一起使用,這是 QML 的一個基本特性,它通過在任何依賴項的值發(fā)生變化時自動更新屬性來強制執(zhí)行屬性之間的關(guān)系。即發(fā)出信號會通知 QML 引擎更新任何涉及屬性的綁定。

    上面示例中如果 author 屬性可寫但沒有關(guān)聯(lián)的 NOTIFY 信號,則文本值將使用 Message::author() 返回的初始值進行初始化,但不會隨此屬性的任何后續(xù)更改而更新。此外,任何從 QML 綁定到屬性的嘗試都會從引擎產(chǎn)生運行時警告。

    建議將 NOTIFY 信號命名為 <property>Changed,其中 <property> 是屬性的名稱。QML 引擎生成的關(guān)聯(lián)屬性更改信號處理程序?qū)⑹冀K采用 on<Property>Changed 形式,無論相關(guān) C++ 信號的名稱如何,因此建議信號名稱遵循此約定以避免任何混淆。

    1.2、使用通知信號的注意事項

    開發(fā)人員應(yīng)確保僅在屬性值實際更改時才發(fā)出屬性更改信號。此外,如果一個屬性或一組屬性不經(jīng)常使用,則允許對多個屬性使用相同的 NOTIFY 信號。這應(yīng)該小心完成以確保性能不會受到影響。

    NOTIFY 信號的存在確實會產(chǎn)生很小的開銷。在某些情況下,屬性的值是在對象構(gòu)造時設(shè)置的,隨后不會更改。在這些情況下,可以將 CONSTANT 屬性而不是 NOTIFY 信號添加到屬性聲明中。

    CONSTANT 屬性應(yīng)僅用于其值僅在類構(gòu)造函數(shù)中設(shè)置和最終確定的屬性。

    1.3、具有對象類型的屬性

    對象類型屬性可從 QML 訪問,前提是對象類型已正確注冊到 QML 類型系統(tǒng)。

    例如:Message 類型可能具有 MessageBody* 類型的 body 屬性

    class Message : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(MessageBody* body READ body WRITE setBody NOTIFY bodyChanged)
    public:
        MessageBody* body() const;
        void setBody(MessageBody* body);
    };
     
    class MessageBody : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString text READ text WRITE text NOTIFY textChanged)
    // ...
    }

    假設(shè) Message 類型已在 QML 類型系統(tǒng)中注冊,

    允許將其用作 QML 代碼中的對象類型:

    Message
    {
        // ...
    }

    如果 MessageBody 類型也注冊到類型系統(tǒng),則可以將 MessageBody 分配給 Message body 屬性:

    Message 
    {
        body: MessageBody 
        {
            text: "Hello, world!"
        }
    }

    1.4、具有對象列表類型的屬性

    包含 QObject 派生類型列表的屬性也可以暴露給 QML。然而,應(yīng)該使用 QQmlListProperty 而不是 QList<T> 作為屬性類型。 這是因為 QList 不是 QObject 派生的類型,因此無法通過 Qt 元對象系統(tǒng)提供必要的 QML 屬性特征,例如修改列表時的信號通知。

    例如,下面的 MessageBoard 類有一個 QQmlListProperty 類型的消息屬性,用于存儲 Message 實例列表:

    class MessageBoard : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QQmlListProperty<Message> messages READ messages)
    public:
        QQmlListProperty<Message> messages()
        {
            return QQmlListProperty<Message>(this, 0, &MessageBoard::append_message);
        }
     
    private:
        static void append_message(QQmlListProperty<Message> *list, Message *msg)
        {
            MessageBoard *msgBoard = qobject_cast<MessageBoard *>(list->object);
            if (msg)
                msgBoard->m_messages.append(msg);
        }
        QList<Message *> m_messages;
    };
    QQmlListProperty 的模板類類型(在本例中為 Message)必須在 QML 類型系統(tǒng)中注冊。

    1.5、分組屬性

    任何只讀的對象類型屬性都可以作為分組屬性從 QML 代碼訪問。這可用于公開一組相關(guān)屬性,這些屬性描述了類型的一組屬性。

    例如,假設(shè) Message::author 屬性的類型是 MessageAuthor 而不是簡單的字符串,具有 name email 的子屬性:

    class MessageAuthor : public QObject
    {
        Q_PROPERTY(QString name READ name WRITE setName)
        Q_PROPERTY(QString email READ email WRITE setEmail)
    public:
        ...
    };
     
    class Message : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(MessageAuthor* author READ author)
    public:
        Message(QObject *parent)
            : QObject(parent), m_author(new MessageAuthor(this))
        {
        }
        MessageAuthor *author() const 
        {
            return m_author;
        }
    private:
        MessageAuthor *m_author;
    };

    可以使用 QML 中的分組屬性語法編寫 author 屬性:

    Message 
    {
        author.name: "Alexandra"
        author.email: "alexandra@mail.com"
    }

    分組屬性是只讀的,并且在構(gòu)造時由父對象初始化為有效值。

    分組屬性的子屬性可以從 QML 修改,但分組屬性對象本身永遠不會改變,

    二、暴露方法

    QObject 派生類型的任何方法都可以從 QML 代碼訪問,只要它滿足其中一項:

    • Q_INVOKABLE() 宏標記的公共方法

    • 作為 public slot 的方法

    例如,下面的 MessageBoard 類有一個使用 Q_INVOKABLE 宏標記的 postMessage() 方法,以及一個公共槽的 refresh() 方法:

    class MessageBoard : public QObject
    {
        Q_OBJECT
    public:
        Q_INVOKABLE bool postMessage(const QString &msg) 
        {
            qDebug() << "Called the C++ method with" << msg;
            return true;
        }
     
    public slots:
        void refresh() 
        {
            qDebug() << "Called the C++ slot";
        }
    };

    如果將 MessageBoard 的實例設(shè)置為文件 MyItem.qml 的上下文數(shù)據(jù),則 MyItem.qml 可以調(diào)用兩個方法,如下例所示:

    int main(int argc, char *argv[]) 
    {
        QGuiApplication app(argc, argv);
     
        MessageBoard msgBoard;
        QQuickView view;
        view.engine()->rootContext()->setContextProperty("msgBoard", &msgBoard);
        view.setSource(QUrl::fromLocalFile("MyItem.qml"));
        view.show();
     
        return app.exec();
    }
    // MyItem.qml
    import QtQuick 2.0
     
    Item 
    {
        width: 100; height: 100
     
        MouseArea 
        {
            anchors.fill: parent
            onClicked: 
            {
                var result = msgBoard.postMessage("Hello from QML")
                console.log("Result of postMessage():", result)
                msgBoard.refresh();
            }
        }
    }

    如果 C++ 方法具有 QObject* 類型的參數(shù),則可以使用對象 id 或引用該對象的 JavaScript 變量值從 QML 傳遞參數(shù)值。

    QML 支持調(diào)用重載的 C++ 函數(shù)。 如果存在多個同名但參數(shù)不同的 C++ 函數(shù),則會根據(jù)提供的參數(shù)數(shù)量和類型調(diào)用正確的函數(shù)。

    當從 QML 中的 JavaScript 表達式訪問時,從 C++ 方法返回的值將轉(zhuǎn)換為 JavaScript 值。

    三、暴露信號

    QObject 派生類型的任何公共信號都可以從 QML 代碼訪問。

    QML 引擎自動為從 QML 使用的 QObject 派生類型的任何信號創(chuàng)建信號處理程序。信號處理程序始終命名為 on<Signal>,其中 <Signal> 是信號的名稱,首字母大寫。 信號傳遞的所有參數(shù)都可以通過參數(shù)名稱在信號處理程序中使用。

    例如,假設(shè) MessageBoard 類有一個帶有單個參數(shù)主題的 newMessagePosted() 信號:

    class MessageBoard : public QObject
    {
        Q_OBJECT
    public:
       // ...
    signals:
       void newMessagePosted(const QString &subject);
    };

     如果 MessageBoard 類型已注冊到 QML 類型系統(tǒng),則在 QML 中聲明的 MessageBoard 對象可以使用名為 onNewMessagePosted 的信號處理程序接收 newMessagePosted() 信號,并檢查主題參數(shù)值:

    MessageBoard 
    {
        onNewMessagePosted: (subject)=> console.log("New message received:", subject)
    }

    與屬性值和方法參數(shù)一樣,信號參數(shù)必須具有 QML 引擎支持的類型。(使用未注冊的類型不會產(chǎn)生錯誤,但處理程序?qū)o法訪問參數(shù)值。)

    請注意:QML引擎無法區(qū)分名稱相同但參數(shù)不同的信號,類可能有多個同名的信號,但只有最后一個信號可以作為 QML 信號訪問。

    上述就是小編為大家分享的將C++ 類型屬性暴露給QML的示例分析了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

    向AI問一下細節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI