C++ 调用QQmlPropertyMap子级的子级插槽?

C++ 调用QQmlPropertyMap子级的子级插槽?,c++,qml,qt5,qt-signals,qqmlpropertymap,C++,Qml,Qt5,Qt Signals,Qqmlpropertymap,在将其标记为“无法调用QQmlPropertyMap子类中可从QML调用的插槽或Q_”的副本之前,请阅读最终响应() 我正在设计一个从QQmlPropertyMap继承的类(称之为MyBaseClass)。它为我的系统实现了一些额外的行为,然后由从MyBaseClass导入的其他类使用(例如ChildClass) 在QML(QtQuick)中,我希望调用ChildClass的插槽(mySlot())。当我尝试时,我在应用程序输出中遇到以下问题(提到MyBaseClass),即使我只使用Child

在将其标记为“无法调用QQmlPropertyMap子类中可从QML调用的插槽或Q_”的副本之前,请阅读最终响应()


我正在设计一个从QQmlPropertyMap继承的类(称之为
MyBaseClass
)。它为我的系统实现了一些额外的行为,然后由从
MyBaseClass
导入的其他类使用(例如
ChildClass

在QML(QtQuick)中,我希望调用
ChildClass
的插槽(
mySlot()
)。当我尝试时,我在应用程序输出中遇到以下问题(提到
MyBaseClass
),即使我只使用
ChildClass

qrc:/main.qml:17: TypeError: Property 'mySlot' of object MyBaseClass(0x55f88ef86b50) is not a function
qrc:/main.qml:24: TypeError: Property 'mySlot' of object MyBaseClass(0x55f88ef86b50) is not a function
我还尝试实现从QML发送信号,但在尝试绑定到QML发出的信号时遇到了类似的问题。(我不是在添加这个例子。)

对于那些建议我只将QQmlPropertyMap继承到ChildClass中的人(除了MyBaseClass之外,它已经通过受保护的方法对MyBaseClass进行了适当的继承和初始化),结果并不理想:

/home/jwerner/Projects/InheritanceTest-simple/ChildClass.h:8: warning: direct base 'QQmlPropertyMap' is inaccessible due to ambiguity:
    class ChildClass -> class MyBaseClass -> class QQmlPropertyMap
    class ChildClass -> class QQmlPropertyMap
我的“直觉”告诉我,问题是我没有用“Qt方式”做事,但我不知道这是什么

下面是演示该问题的最低示例代码。(我省略了.pro文件,因为它制作起来很简单。)

MyBaseClass.h

#include <QQmlPropertyMap>

class MyBaseClass : public QQmlPropertyMap
{
    Q_OBJECT
public:
    explicit MyBaseClass(QObject *parent = nullptr)
        : QQmlPropertyMap(this, parent)
    {}

};
#include "MyBaseClass.h"
#include <QObject>
#include <QDebug>

class ChildClass : public MyBaseClass
{
    Q_OBJECT
public:
    ChildClass(QObject *parent = nullptr)
        : MyBaseClass(parent) {}

public slots:
    void mySlot() {
        qDebug() << "This is mySlot";
    };
};
main.cpp

int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    auto childData = new ChildClass();

    engine.rootContext()->setContextProperties({
        QQmlContext::PropertyPair{"childData",  QVariant::fromValue(childData)},
    });
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
        &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

intmain(intargc,char*argv[])
{
#如果QT\u版本setContextProperties({
QQmlContext::PropertyPair{“childData”,QVariant::fromValue(childData)},
});
const-QUrl-url(QStringLiteral(“qrc:/main.qml”);
QObject::connect(&engine),&QQmlApplicationEngine::objectCreated,
&应用程序,[url](QObject*obj,const-quorl和objUrl){
如果(!obj&&url==objUrl)
QCoreApplication::退出(-1);
},Qt::QueuedConnection);
引擎加载(url);
返回app.exec();
}

注意,2参数
qqqmlPropertyMap
构造函数是一个模板构造函数,需要[most]派生类的类型(文档对此可能更清楚,但这是使其与automagic注册一起工作的唯一方法)。它所见过的唯一类型是
MyBaseClass

qrc:/main.qml:17: TypeError: Property 'mySlot' of object MyBaseClass(0x55f88ef86b50) is not a function
qrc:/main.qml:24: TypeError: Property 'mySlot' of object MyBaseClass(0x55f88ef86b50) is not a function
您需要将派生类的类型传递给该构造函数,例如,通过将受保护的
MyBaseClass
构造函数模板化,并赋予其与
QQmlPropertyMap
相同的签名,然后从
MyChildClass
调用该签名。只有在CRTP模板类不添加任何属性、信号或插槽的情况下,制作
MyBaseClass
的替代方法才有效

因此:

然后:

#include "MyBaseClass.h"
#include <QObject>
#include <QDebug>

class ChildClass /* final, or see below */ : public MyBaseClass
{
    Q_OBJECT
public:
    ChildClass(QObject *parent = nullptr)
        : MyBaseClass(this, parent) {}   // notice the additional argument

protected:
    // if this class is not final, then add:
    template <typename Derived>
    ChildClass(Derived *derived, QObject *parent = nullptr)
         : MyBaseClass(derived, parent) {}

public slots:
    void mySlot() { qDebug() << "This is mySlot"; };
};
#包括“MyBaseClass.h”
#包括
#包括
类ChildClass/*final,或参见下面的*/:public MyBaseClass
{
Q_对象
公众:
子类(QObject*parent=nullptr)
:MyBaseClass(this,parent){}//请注意附加的参数
受保护的:
//如果该类不是最终类,则添加:
模板
子类(派生的*派生的,QObject*父类=nullptr)
:MyBaseClass(派生的,父级){}
公众时段:

void mySlot(){qDebug()我对此进行了测试,并取得了成功,但我不能说我建议将其作为解决方案。如果它必须了解其派生类型,那么它有点否定了拥有基类的目的

// Forward-declare the derived type so it can be passed to the constructor
class ChildClass;

class MyBaseClass : public QQmlPropertyMap
{
    Q_OBJECT
public:
    explicit MyBaseClass(ChildClass *derivedObj, QObject *parent = nullptr)
        : QQmlPropertyMap(derivedObj, parent)
    {}

};


您提供的链接指向错误报告,该报告链接回,其中包括以下内容:“注意:从QQmlPropertyMap派生类时,使用受保护的双参数构造函数,以确保该类正确注册到Qt元对象系统。”基类(MyBaseClass)JarMan正在执行此操作。尝试将继承从QQmlPropertyMap添加到ChildClass时出错。“/home/jwerner/Projects/InheritanceTest simple/ChildClass.h:8:警告:由于不明确,无法访问直接基'QQmlPropertyMap':class ChildClass->class MyBaseClass->class qqqmlpropertymap class ChildClass->class QQmlPropertyMap”“@jwernerny您无法从QObject进行乘法派生,因此当然,从
QQmlPropertyMap
重新继承将不起作用,这并不意味着我可以确定。“我正在设计一个从QQmlPropertyMap继承的类(称为MyBaseClass)”-这是问题的根源。“Qt方式”需要一个明确的答案来解释为什么这是必要的,以及你想要达到的。也许这是一个不必要的复杂。如果代码不是动态创建的,则代码> QQMLPrimTypMy/<代码>根本不是必需的,在这种情况下,QT 6的可绑定属性执行它。我要做的是创建一种可重用的方式从C++传递数据。接口层到QML显示层。我们接口到的每个东西都有它自己的数据,并且可能有我们需要从UI触发的东西。我们还不知道这些东西的所有数据(它一直在变化),因此有能力创建动态数据是一项要求。关键是使其成为模板构造函数。无需向前声明任何内容,也无需提前知道子类的类型。
QQmlPropertyMap
已经做到了这一点,您基本上可以复制粘贴该想法(当然,必须这样做,只有一种方法).是的,你当然是对的。我发布这篇文章是因为它很有效,但我知道它是糟糕的代码。很高兴有更好的方法。我一直在考虑使用模板。我会尝试一下,并针对我的单元测试来运行它,以获得真正的代码。我认为倾向于先考虑继承,然后再考虑模板。我已经在我们的实际应用程序中进行了测试,它很有效。谢谢
#include "MyBaseClass.h"
#include <QObject>
#include <QDebug>

class ChildClass /* final, or see below */ : public MyBaseClass
{
    Q_OBJECT
public:
    ChildClass(QObject *parent = nullptr)
        : MyBaseClass(this, parent) {}   // notice the additional argument

protected:
    // if this class is not final, then add:
    template <typename Derived>
    ChildClass(Derived *derived, QObject *parent = nullptr)
         : MyBaseClass(derived, parent) {}

public slots:
    void mySlot() { qDebug() << "This is mySlot"; };
};
// Forward-declare the derived type so it can be passed to the constructor
class ChildClass;

class MyBaseClass : public QQmlPropertyMap
{
    Q_OBJECT
public:
    explicit MyBaseClass(ChildClass *derivedObj, QObject *parent = nullptr)
        : QQmlPropertyMap(derivedObj, parent)
    {}

};