【问题标题】:Passing custom c++ type as QML function parameter将自定义 C++ 类型作为 QML 函数参数传递
【发布时间】:2023-06-23 06:10:01
【问题描述】:

我正在尝试使用相应的参数创建自定义类实例并将其传递给 Q_INVOKABLE 函数。 我试图举一个例子来指出我想要做什么。所以基本上我有一个类 Foo 和另一个类 Bar 有一个以 Foo 作为参数的函数。我想在 QML 中调用此函数,但我不知道如何实例化 Foo 以将其作为该函数的参数传递。

编辑 - 有关主要目标的更多信息:

真正的目标是拥有一个包含自定义类对象列表的子类 QAbstractItemModel。然后将使用模型 data() 函数表示该列表。该模型应该以某种方式表示为 QML 中的视图。我也想在运行时填充模型。所以模型类应该有一个函数,它接受一个自定义类实例并将其附加到内部列表中。所以我的方法是在 qml 中创建并传递自定义类实例。我还没有找到任何例子来做那种事情。 这是我所拥有的:

Foo.h

class Foo : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ getName WRITE setName)
public:
    Foo(QString fooName, QObject *parent = 0) : QObject(parent){
        name = fooName;
    }          
    QString getName() const {
        return name;
    }
    void setName(const QString &value){
        name = value;
    }    
private:
    QString name;
};

Bar.h

class Bar : public QObject
{
    Q_OBJECT
public:
    explicit Bar(QObject *parent = 0) : QObject(parent){}

    Q_INVOKABLE void addFoo(const Foo &foo){
        fooList.append(foo);
    } 
private:
    QList<Foo> fooList;
};

ma​​in.cpp

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

    QQmlApplicationEngine engine;
    qmlRegisterType<Foo>("Test", 1, 0, "Foo");
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    engine.rootContext()->setContextProperty("bar", new Bar());    
    return app.exec();
}

ma​​in.qml

import Test 1.0

Window {    
    Button {
        id: addFoo
        text: "Add new Foo to Bar"
        onClicked: {
            bar.addFoo(????)
        }
    }   
}

【问题讨论】:

  • 作为一般规则,在加载 QML 之前设置上下文属性。上下文属性必须在加载引用上下文属性的QML之前设置。它仍然可以工作,但你可能会因此而招致奇怪的错误。

标签: c++ qt qml


【解决方案1】:

您可以通过给Foo 提供一个可以不带参数调用的构造函数来使Foo 可实例化,然后使用CMLDMR 建议的方法,或者添加一个可以创建实例的“工厂”函数。

在后一种情况下,您要么需要使用 Foo* 作为工厂函数的返回值和 addFoo() 的参数,要么将 Foo 更改为带有属性的 Q_GADGET 宏的值类而不是来自QObject

鉴于您在Foo 中没有信号,我会推荐后者。

大概是这样的:

class Foo
{
    Q_GADGET
    Q_PROPERTY(...)

// ....
};


class Bar : public QObject
{
// ...

    Q_INVOKABLE Foo createFoo(const QString &name);
    Q_INVOKABLE void addFoo(const Foo &foo);
};

编辑:它还需要

qRegisterMetaType<Foo>();

【讨论】:

  • 感谢您的回答。当我更改您提到的代码时,我收到以下错误:“错误:未知方法返回类型:Foo”。我错过了什么?
  • 这是编译器错误还是来自 QML 环境?
  • 它来自qml环境,我称之为createFoo函数。
  • 啊,Foo也需要qRegisterMetaType()。将修改答案
  • 是的,这就是问题所在。谢谢!有没有详细介绍该主题的好资源?我想看看如何在 QML 中集成 c++ 的一个很好的例子。
【解决方案2】:

在 QML 中传递对象之前,您应该通过 Foo 创建一个对象。 来源:Qt5 C++ GUI Programming Cookbook. Lee Zhi Eng,第37页

import Test 1.0

Window {
    Foo {
    id: Foo_object
    }    
    Button {
        id: addFoo
        text: "Add new Foo to Bar"
        onClicked: {
            bar.addFoo(Foo_object)
        }
    }   
}

【讨论】:

  • 但我想动态创建 Foo 对象,而不仅仅是预定义的数量。或者我可以总是使用相同的吗?如果我喜欢你说我得到以下错误:“错误:未知方法参数类型:Foo”
  • @Matthias 这真的很难提供帮助,因为不清楚你想赋予这些对象的生命周期。 “我可以一直使用相同的吗”只有一个答案:“这真的取决于您想要实现的目标”。但这是我们在这里无法轻易推断的。一般来说,您可以按照文档here 或使用Instantiator 动态生成实例。