2016-03-15 138 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