如何在QML Javascript中创建和使用C++对象

13

我的应用程序同时使用了C++和QML。

我在C++部分定义了几个对象来访问SQL等内容。

它看起来像这样:

class MyObject : public QObject
{
    Q_OBJECT
public:
    MyObject(QObject *parent = 0);
    Q_INVOKABLE void someFunction(const QString &query);
};

qmlRegisterType<MyObject>("xxx.xxx", 1, 0, "MyObject");

理想情况下,我只需要在Javascript中使用这些对象而不是在QML中使用。

我尝试了很多例子并阅读了所有文档,但仍然无法解决我的问题。

所以我的问题是:

  • 如何在Javascript中实例化一个在C++中定义的对象?我尝试使用var obj = Qt.createComponent("MyObject");,但似乎没有起作用。是否可以按照常规JS样式定义新对象- var obj = new MyObject;
  • 如何在javascript中访问此创建的对象?我尝试使用obj.someFunction("xxx")但出现了错误- TypeError: Property 'someFunction' of object QQmlComponent(0x3605f5c0) is not a function.我在这里做错了什么?我的对象派生自QObject,而不是QQmlComponent。

有人回答了这个问题,然后它就在我的列表里出现了。 :) 在这里使用上下文属性不是一个好的解决方案吗?我唯一能看到的限制是它不能随意实例化,而是在主QML文件被加载之前。 - BaCaRoZzo
4个回答

4

父级应该是谁?还是在其有用性结束时动态删除它? - Jon McClung
QML中未设置父对象的对象由垃圾回收器管理,除非特别标记。请注意QObject父对象和(视觉上的)parentItem之间存在区别。 - OliJG

3

文档已经很清晰了,但混淆似乎在QML方面。以下内容可以帮助您入门:

//C++
class MyObject : public QObject
{
    Q_OBJECT
public:
    MyObject(QObject *parent = 0);
    Q_INVOKABLE void someFunction(const QString &query) { qDebug() << query;}
};
....
qmlRegisterType<MyObject>("foo.bar", 1, 0, "MyObject");

以下是QML代码:
import foo.bar 1.0 //This is your register type
Item {
  MyObject { //here's the instance, remember it is declarative
    id: myObject;
  }
  MyObject {
    id: myObjectInstance2
  }
  Button {
    onClicked: {
      myObject.someFunction("doSomething"); //here is using a reference
      myObjectInstance2.someFunction("doSomethingElse");
    }
  }
}

点击之后,您应该能够在输出中看到字符串(我没有编译或测试过)。请确保在您的主类中注册类型。

如果您正在移动设备上使用SQL,请查看本地存储对象。它是一个与SQLite一起工作的非常简单的回调API。对于桌面应用程序,我使用它并没有遇到太多麻烦。返回列表有点麻烦,因此请尽量坚持使用简单类型以便于JavaScript集成。

希望这可以帮到您。我非常喜欢在QML中工作,一旦您学会了它就很有趣(1-2周的时间足以掌握足够的熟练度来工作)。


谢谢@Daniel B. Chapman,但这不是我需要的。我对QML语法非常熟悉,所以我问了如何在JS中实现。我的对象有点像ActiveRecord。实际上它与Postgresql一起工作。该对象没有可视化表示,因此我认为将其嵌入到QML树中没有意义。它可以被多次创建或销毁,也可以在某个步骤更改。我需要它就像Qt.someFunction()或Math.someFunction()一样。 - folibis
你的问题在于需要将你的类实例化为一个组件实例。使用这种方法,你需要将它附加到树上,以便可以引用它。基本上是 var comp = Qt.create component('myQmlFile.qml'); var instance = comp.createObject(parent); 这只是动态声明。我应该指出,静态方法是可能的(这是一个功能请求,最后我检查过),但我找到的解决方案是创建一个实例(动态或静态),然后从那里使用方法。 - Daniel B. Chapman
哎呀,这太糟糕了!据我所知,将C++对象作为JS库暴露给QML是不可能的。使用如此原始的技术真是个坏主意。我基于这个构建了我的新项目,现在完全不知道该怎么处理所有的代码了。 - folibis
1
这并不是什么大不了的事情,你可以将其公开。你需要理解JavaScript方面需要一个起点。我经常从QML中使用C++。 - Daniel B. Chapman
我有一个非常相似的问题,你能否看一下:http://stackoverflow.com/questions/39379345/module-is-not-installed-registering-custom-c-wrapper-for-qml - Aras

2

这里有一个关于想象中的TextFile类的例子。首先,我们需要一个工厂类,如之前所建议的:

// Factory class
class Creator : public QObject
{
    Q_OBJECT
    public:
    Q_INVOKABLE QObject* createObject(const QString& typeName, const QVariantMap& arguments);
};

QObject* Creator::createObject(const QString& typeName, const QVariantMap& arguments)
{
    if (typeName == "TextFile")
    {
        QString filePath = arguments.value("filePath").toString();
        TextFile::OpenMode openMode =
                qvariant_cast<TextFile::OpenMode>(arguments.value("openMode", TextFile::ReadWrite));
        QString codec = arguments.value("codec", "UTF-8").toString();
        return new TextFile(qmlEngine(this), filePath, openMode, codec);
    }

    Q_ASSERT(false);
    return nullptr;
}

注意:这个类比必要的更复杂。它应该创建多种类型。既然我们已经有了工厂类,我们需要告诉QML/QJSEngine在调用TextFile的new运算符时该做什么。
    QJSValue creator = engine.newQObject(new Creator());
    engine.globalObject().setProperty("_creator", creator);
    engine.evaluate("function TextFile(path, mode) { return _creator.createObject(\"TextFile\", { filePath: path, openMode: mode }); }");

现在我们可以按照需要实例化我们的TextFile,甚至可以带参数:
var myFile = new TextFile("/path/to/file", TextFile.ReadWrite);

感谢这个答案的作者


2

你可以使用

QQmlApplicationEngine engine;
engine.globalObject().setProperty("CppCreator", engine.newQObject(&CppCreator::GetInstance()));

CppCreator是一个创建其它C++对象的QObject。

Q_INVOKABLE QObject* Create(const QString& type_name);

然后,您可以在QML JS中创建C++对象,如下所示:
var test = CppCreator.Create("Your Type");

虽然不是完美的,但满足了我的需求。希望能对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接