2016-03-15 136 views
0

我想在C++中使用工廠類來創建可在QML中使用/訪問的對象。但是,如何在QML中訪問這種新創建的對象?這是可能的JavaScript?如何在C++中創建對象並在QML中訪問它

在C++我的工廠類創建一個對象employee其可以是ManagerSalesPersonEngineer類型的所有從Employee的。這裏是代碼:

class EmployeeFactory : public QObject 
{ 
    Q_OBJECT 
public: 
    enum 
    { 
     MANAGER, 
     SALES_PERSON, 
     ENGINEER 
    }; 
    explicit EmployeeFactory(QObject *parent = 0); 

    Q_INVOKABLE Employee *createEmployee(int type) 
    { 
     if (type == MANAGER) 
     { 
      qDebug() << "createEmployee(): Manager created"; 
      return new Manager; 
     } 
     else if(type == SALES_PERSON) 
     { 
      qDebug() << "createEmployee(): SalesPerson created"; 
      return new SalesPerson; 

     } 
     else if(type == ENGINEER) 
     { 
      qDebug() << "createEmployee(): Engineer created"; 
      return new Engineer; 
     } 

     qDebug() << "createEmployee(): Nothing created"; 
     return 0; 
    } 


signals: 

public slots: 
}; 

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

    QQmlApplicationEngine engine; 

    EmployeeFactory * factory = new EmployeeFactory; 

    qmlRegisterType<Employee>("MyModel", 1, 0, "employee"); 

    engine.rootContext()->setContextProperty("factory", factory); 

    engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 

    return app.exec(); 
} 

現在在我的QML代碼中,我想創建員工並訪問它。

Window { 
    visible: true 

    MouseArea { 
     anchors.fill: parent 
     onClicked: { 

      // how do I access the return value `employee` here or how 
      // do I return/access employee here 
      employee e = factory.createEmployee(0) // This doesn't work, result in Expected token ';' error 

      // once I have the employee, I would like to set its attributes like 
      // e.name: "David" 
     } 
    } 

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

有錯字管線'僱員E = factory.createEmployee(0)'。使用'員工'。 – vcp

+0

@vcp如果我執行'employee'而不是錯誤地運行,但是如果我在下一行訪問它,則表示'employee is not defined'。 – zar

+0

不要忘記在QML'import MyModel 1.0'中導入語句。 – vcp

回答

1

如果你的員工都是基於QObject,在這種情況下,你不需要在所有做任何事情來使用QML的對象,作爲元系統會照顧。缺點是QObject是相當巨大的,所以如果你有數百萬員工,你肯定不會那麼想。但是,成千上萬或更少的應該沒問題。

由於JS不是強類型語言,它不會是employee e =...而是var e = factory.createEmployee(0)如果您希望在屬性中鍵入它,您必須將其註冊爲QML類型,它可以是常規或作爲一個非創建者,分別使用qmlRegisterType()qmlRegisterUncreatableType()函數,後者是一種可以訪問和使用但不能從QML創建的類型。

我假設你已經暴露了作爲上下文屬性公開的工廠。

如果你不希望你的員工是QObject導出,然後你將不得不放棄直接使用對象從QML(不,你不這樣做,你可以簡單地使用Q_GADGET作爲vpicaver說明) ,您可以使用Q_DECLARE_METATYPE()將它們註冊到Qt元類型系統,這將允許您將它們用作QML,中的參數,但爲了訪問它們的數據,必須使用派生的訪問器/控制器類的QObject,它將將員工數據從C++返回到QML。或者您可以使用模型來管理,並將成員公開爲模型角色,在這種情況下,您需要實施例如QAbstractListModel

此外,當從C++創建基於對象的QObject並在QML中使用它們時,請記住對象生存期。您可以明確指定QML或C++是否管理所有權和生命週期,並且在使用中我已經公平地分享了與QML刪除對象相關的問題,導致崩潰,此時QML所有權似乎相當笨拙,但行爲僅在更復雜,高度動態的場景中展示,對於「典型」的QML使用,它可能是好的。

+0

謝謝,最後一段很有趣。我沒有考慮過擔心對象的生命週期,特別是因爲我正在用C++創建它們。我如何指定C++是所有者,並且它們不會被自動刪除? – zar

+0

是的,您可以設置CPP所有權,這種方式只能通過C++刪除對象,您將無法使用QML中的destroy()。 – dtech

+0

默認情況下,從插槽返回到QML的任何'QObject'都將具有'QQmlEngine :: JavaScriptOwnership'。我在這裏描述了這個bug,我也將它發佈到Qt bug跟蹤器中,但是到目前爲止還沒有工作已經完成,即使它被標記爲關鍵:http://stackoverflow.com/questions/33792876/qml-garbage-collection - 刪除的對象,仍然在使用 – dtech