如何将带有自定义对象的容器从C ++传递到QML?

时间:2018-10-25 12:08:16

标签: c++ qt qml qt5

我对C ++有所了解,但是我对QML还是很陌生。
我想将容器中的多个自定义C ++对象传递给QML,但是这样做很麻烦。
所提供的代码已缩小为基本内容。

我可以在通过setContextProperty注册的单个对象中与QML进行通信,这很好用。但是,如果我尝试使用QHash这样做,则会出现错误:

std::shared_ptr

也许您可以帮助我或给我指示? 谢谢你。

更新
谢谢derM,这是我的尝试:

我在头文件的末尾添加了‘QVariant::QVariant(void*)’ is private within this context‘ 。我已将容器更改为QVariantMap。
如果我尝试:QVariant qvtest1(test1); 我收到错误消息:

Q_DECLARE_METATYPE(MyData);

但这可行:

no matching function for call to ‘QVariant::QVariant(MyData&)’

但是我再次收到以下错误:setContextProperty(“ mymap”,&mymap); 错误:

QVariant qvtest1, qvtest2;  
qvtest1.setValue(test1);  
qvtest2.setValue(test2);  

代码已相应调整。

更新2
谢谢eyllanesc,您的方法正在奏效!
但是,我现在遇到了QML中的相关问题。 看来我无法从QML访问所有QMap函数。

例如:

calling a private constructor of class 'QVariant'

相同的问题:

var test_data = mymap["three"]  // works fine  
var test_data2 = mymap.find("two").value()  // results in: Property 'find' of object [object Object] is not a function

我正在使用Qt 5.11.1
这是错误还是我错过了什么?

C ++代码
mydata.hpp:

var tmp1 = mydata_qml_object // object was created before  
mymap["four"] = tmp1 // works fine  
mymap.insert("four", tmp1) // Property 'insert' of object [object Object] is not a function  

mydata.cpp:

#ifndef MYDATA_HPP  
#define MYDATA_HPP

#include <QObject>
#include <QString>

class MyData : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString name READ get_name WRITE set_name NOTIFY nameChanged)

  public:
    explicit MyData(QObject *parent = nullptr);
    MyData(QString name);
    MyData(const MyData &other);
    MyData(MyData &&other) = delete;
    MyData &operator=(const MyData &other);
    MyData operator=(MyData &&other) = delete;
    ~MyData() override = default;

  signals:
    void nameChanged();

  public slots:
    void set_name(const QString &name);
    QString get_name();

  private:
    QString _name;
};

Q_DECLARE_METATYPE(MyData);

#endif // MYDATA_HPP

main.cpp:

#include "mydata.hpp"

MyData::MyData(QObject *parent)
    : QObject(parent)
{
}

MyData::MyData(QString name)
    : _name(name)
{
}

MyData::MyData(const MyData &other)
{
    _name = other._name;
}

MyData &MyData::operator=(const MyData &other)
{
    if (this != &other)
    {
        _name = other._name;
        return *this;
    }
}

void MyData::set_name(const QString &name)
{
    _name = name;
}
QString MyData::get_name()
{
    return _name;
}

1 个答案:

答案 0 :(得分:0)

根据the docs,从QObject继承的类不能具有复制构造函数或赋值运算符:

  

没有复制构造函数或赋值运算符

     

QObject既没有复制构造函数,也没有赋值运算符。   这是设计使然。实际上,它们是被声明的,但是是私下声明的   Q_DISABLE_COPY()宏部分。实际上,所有Qt类   从QObject派生(直接或间接),请使用此宏进行声明   他们的复制构造函数和赋值运算符是私有的。的   在关于Qt的身份与价值的讨论中找到了推理   对象模型页面。

     

主要结果是您应该使用指向QObject的指针(或指向   您的QObject子类),否则您可能会被诱惑使用   您的QObject子类作为值。例如,没有副本   构造函数,您不能使用QObject的子类作为要   存储在容器类之一中。您必须存储指针。

另一方面,如果希望从QObject继承的类支持QMetaType用作QVariant,则必须将其传递给指针,因为如上所述,QObject没有复制构造函数,但是指针是可复制的。

//mydata.h
#ifndef MYDATA_H
#define MYDATA_H

#include <QObject>
class MyData : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString name READ get_name WRITE set_name NOTIFY nameChanged)
public:
    explicit MyData(QObject *parent = nullptr);
    MyData(const QString & name);
    ~MyData() override = default;
signals:
    void nameChanged();
public slots:
    void set_name(const QString &name);
    QString get_name();
private:
    QString _name;
};
Q_DECLARE_METATYPE(MyData*)
#endif // MYDATA_H

//mydata.cpp

#include "mydata.h"

MyData::MyData(QObject *parent) : QObject(parent)
{}
MyData::MyData(const QString & name)
    : _name(name){}
void MyData::set_name(const QString &name)
{
    if(_name == name) return;
    _name = name;
    emit nameChanged();
}
QString MyData::get_name()
{return _name;}

您指出setValue可以工作,是否购买了它可以工作?,除了此方法用于不支持QVariant的类型之外,因此它们可能会接受任何类型的数据,必须做的就是传递指针:

MyData test1("Hi");
MyData test2("Hello");
QMap<QString, QVariant> mymap;
QVariant qvtest1 = QVariant::fromValue(&test1); 
QVariant qvtest_1, qvtest_2;
qvtest_1.setValue(&test1);
qvtest_2.setValue(&test2);

另一方面是setContextProperty,它接受QVariant或指向QObject的指针,在您的第一种情况下,您传递QObject的正确方法是传递指针,在第二种情况下,您传递QQariant,因此没有可以复制的问题。

engine->rootContext()->setContextProperty("test1", &test1);
engine->rootContext()->setContextProperty("mymap", mymap);

最后,必须将一个可复制对象传递给setContextProperty。


qmlRegisterType仅记录可以通过信号传输的类型,但这不能保证其有效,这是必要条件,但由于不能复制而还不够,因此必须使用{{1 }}。