2017-04-22 62 views
0

我有一個文件mygadget.h如何通過Q_PROPERTY

#include <QObject> 

class MyGadget { 
    Q_GADGET 
    Q_PROPERTY(int value READ value CONSTANT) 

public: 
    MyGadget() = default; 
    MyGadget(int i) 
     : _value{i} 
    { 
    } 

    int value() const 
    { 
     return _value; 
    } 

private: 
    int _value{0}; 
}; 
Q_DECLARE_METATYPE(MyGadget) 
Q_DECLARE_METATYPE(MyGadget*) 

Context類持有MyGadget一個實例,並暴露了一個指向它定義的Q_GADGET MyGadget暴露一個指向Q_GADGET到QML經由Q_PROPERTY QML:

#include <QObject> 
#include "mygadget.h" 

class Context : public QObject 
{ 
    Q_OBJECT 
    Q_PROPERTY(MyGadget* gadget READ gadget CONSTANT) 
public: 
    explicit Context() 
     : QObject{nullptr} 
    { 
    } 

    MyGadget* gadget() { 
     return &_gadget; 
    } 
private: 
    MyGadget _gadget{4}; 
}; 

Context一個實例中main創建並暴露於QML作爲上下文屬性:

#include <QGuiApplication> 
#include <QQuickView> 
#include <QString> 
#include <QQmlContext> 

#include "context.h" 

int main(int argc, char *argv[]) 
{ 
    QGuiApplication app(argc, argv); 

    QQuickView view; 
    Context c; 

    // register MyGadget 
    qmlRegisterUncreatableType<MyGadget>("Test", 1, 0, "MyGadget", ""); 
    qRegisterMetaType<MyGadget*>(); // <- removing this doesn't change anything 

    // make Context instance a context propery 
    view.rootContext()->setContextProperty("context", &c); 

    // show QML 
    view.setSource(QUrl{QStringLiteral("qrc:/main.qml")}); 
    view.show(); 

    return app.exec(); 
} 

與此使用的QML文件

import QtQuick 2.5 
import Test 1.0 

Rectangle { 
    height: 600 
    width: 800 
    visible: true 

    Text { 
     text: qsTr("Hello World " + context.gadget.value) 
     anchors.centerIn: parent 
    } 
} 

一切編譯罰款,但運行它沒有文本不顯示時和QML發出警告

qrc:/main.qml:9: TypeError: Cannot read property 'value' of null.

如果我刪除請撥打的main和QML文件中的相應import Test 1.0,而不是顯示文本「Hello World undefined」。

我把它像預期的那樣打印的「Hello World 4」的唯一途徑是擁有Context::gadget返回存儲MyGadget對象的副本,而不是一個指針給它,或使MyGadget一個Q_OBECT代替。但是這兩個在我的真實應用程序中都不是可行的選項,因爲我需要引用語義,但在其他地方,我還希望在本例中對於類012sh對應的類具有值語義。

我怎樣才能讓QML讀取正確的屬性值?

回答

1

小工具從根本上受限於設計,你不能在QML的指針基礎上工作,你必須使用實例,這也意味着按值傳遞和返回。這也意味着您所做的任何操作都將應用於副本,而不是您想要的實際對象。

有一種方法可以解決這個問題,通過使用PIMPL,基本上小工具對象是一個指針,也就是說,它只有一個成員變量,它是一個指向實際對象數據實現的指針,它是一個單獨的對象。

這使得小工具對象的複製非常便宜,因爲它只是一個指針,並且所有副本都引用相同的對象數據,因此您的更改不會丟失。

更新:

無論如何,如果你的小工具屬性僅僅是一個int或其他原語爲您的評論說,然後把它作爲一個int屬性。你可以有通知的屬性,QML會抱怨說,如果你在綁定中使用它們,他們沒有通知,但你可以簡單地傳遞一個永遠不會發出並且被設置的虛擬信號。

而且,即使你使用PIMPL,也不需要在每個原始基礎上動態分配,或者根本不需要動態分配。指針並不在乎它指向什麼,除非存在內存變得無效的危險,指針 - 懸掛。

+0

很傷心。我的真實世界的應用程序'上下文'擁有大量的物理量(羣衆,力量,速度......),它們由仿真代碼更新。一旦所有這些都更新了,我希望'Context'對象通知QML更新視圖。我明確地不想每次更改其中一個數量時更新它,因此它們不需要信號。另一方面,這些基本上只是原始類型的包裝,只是爲了使用PIMPL而將它們分配到堆中,這在應用程序的其餘部分中是沒有意義的。 – Corristo

+0

想想看,這看起來更像是一個明確的設計決定,而不是技術限制,畢竟當我沒有註冊'MyGadget *'時行爲發生變化。你碰巧知道爲什麼做出這個決定? – Corristo

+0

閱讀我的答案更新。看來(再次)你試圖以一種錯誤的方式解決問題。我不知道爲什麼這樣的小工具是以這種方式實現的,但很多Qt對我來說都沒有任何意義。我只是最近才發現的,並嘗試幾乎所有我能想到的http://stackoverflow.com/questions/42843942/q-gadget-vs-an-accessor-object-for-manipulating-a-polymorphic-tree-of -c-object在我發現這個之前https://bugreports.qt.io/browse/QTBUG-54321 – dtech