[英]How to pass container with custom objects from C++ to QML?
我对C ++有所了解,但我对QML还是很陌生。
我想将容器中的多个自定义C ++对象传递给QML,但是这样做很麻烦。
所提供的代码缩小了基础范围。
我可以在通过setContextProperty注册的单个对象中与QML通信,这很好。 但是,如果我尝试使用QHash进行操作,则会收到错误消息:
‘QVariant::QVariant(void*)’ is private within this context‘
也许您可以帮助我或给我指示? 谢谢你
更新:
谢谢derM,这是我的尝试:
我添加了: Q_DECLARE_METATYPE(MyData);
在头文件的末尾。 我已将容器更改为QVariantMap。
如果我尝试:QVariant qvtest1(test1); 我得到错误:
no matching function for call to ‘QVariant::QVariant(MyData&)’
但这有效:
QVariant qvtest1, qvtest2;
qvtest1.setValue(test1);
qvtest2.setValue(test2);
但是我又收到一个错误:setContextProperty(“ mymap”,&mymap); 错误:
calling a private constructor of class 'QVariant'
代码会相应调整。
更新2
谢谢eyllanesc,您的方法正在起作用!
但是,我现在遇到了QML中的相关问题。 看来我无法从QML访问所有QMap函数。
例如:
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
同样的问题:
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
我正在使用Qt 5.11.1
这是错误还是我错过了什么?
C ++代码
mydata.hpp:
#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
mydata.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;
}
main.cpp中:
#include <mydata.hpp>
#include <QGuiApplication>
#include <QMap>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQmlContext>
#include <QQuickView>
#include <iostream>
int main(int argc, char *argv[])
{
MyData test1("Hi");
MyData test2("Hello");
QMap<QString, QVariant> mymap; // QVariantMap
QVariant qvtest1(test1); // error: no matching function for call to ‘QVariant::QVariant(MyData&)’
//working:
QVariant qvtest1, qvtest2;
qvtest1.setValue(test1);
qvtest2.setValue(test2);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
auto *engine = new QQmlEngine;
QQuickView view;
QQmlContext *ctxt = view.rootContext();
// this is working:
qmlRegisterType<MyData>("MyData", 1, 0, "MyData");
engine->rootContext()->setContextProperty("test1", &test1);
// this produces an error: calling a private constructor of class 'QVariant'
engine->rootContext()->setContextProperty("mymap", &mymap);
QQmlComponent component(engine, QUrl("qrc:/main.qml"));
QQmlEngine::setObjectOwnership(engine, QQmlEngine::CppOwnership);
QObject *object = component.create();
return app.exec();
}
根据docs ,从QObject
继承的类不能具有复制构造函数或赋值运算符:
没有复制构造函数或赋值运算符
QObject既没有复制构造函数,也没有赋值运算符。 这是设计使然。 实际上,它们是通过宏Q_DISABLE_COPY()的私有部分声明的。 实际上,所有从QObject派生的Qt类(直接或间接)都使用此宏将其复制构造函数和赋值运算符声明为私有。 可以在“ 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,正确的方法是传递指针,在第二种情况下,您传递QVariant,因此没有问题。可以复制。
engine->rootContext()->setContextProperty("test1", &test1);
engine->rootContext()->setContextProperty("mymap", mymap);
最后,必须将一个可复制对象传递给setContextProperty。
qmlRegisterType
仅记录可以通过信号传输的类型,但这不能保证它可以工作,这是必要条件,但由于它不可复制,因此还不够,因此必须使用MyData*
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.