我的目标是将自定义C ++类“Contact”的实例作为从C ++类“ContactHelper”发出的信号“contactFound”的参数“contact”传递给QML;并在QML中的“onContactFound”信号处理程序中访问信号参数“contact”的属性。
从QML方面来看,对象“contact”基本上是一个数据结构,有2个只读属性,没有方法。
我尝试了两种方法,这两种方法都在本问题底部的示例代码中显示。 编辑:在此问题的原始版本中,均未奏效。感谢@BaCaRoZzo的评论,方法1现在有效(从而解决了我的直接问题)。
方法1)“联系人”以QT documentation中的自定义类型示例“阻止”和“消息”为模型。即“Contact”是通过 qRegisterMetaType 声明的,并且不是基于 QObject ,而是使用 Q_GADGET 宏(来自BaCaRoZzo的输入)。
这种方法既可以通过引用(& contact)和值(contact)传递给信号,但是当通过指针/地址(* contact)传递时会失败。
方法2)“Contact2”基于 QObject ,通过 qmlRegisterType 声明,并通过指针/地址(* contact2)传递。
代码编译并运行,但这两种方法都没有给我预期的信号参数属性访问。
方法1)在QML中,“onContactFound”的参数“contact”有效,但联系人的属性未定义。 编辑:通过将缺少的 Q_GADGET 宏添加到contact.h来解决此问题。
在QML中方法2)未定义“onContactFound2”的参数“contact”!
编辑:鉴于方法1现在有效,我可以在我的实际代码中使用它,并略微改变这个问题的重点,即:
a)什么阻止方法2(对象/ qmlRegisterType /由指针*传递)?
b)假设两种方法都可以工作,哪种方法最适合通过C ++到QML的信号参数传输轻量级只读数据结构(少数字符串属性+ 1字符串数组属性)?
我正在使用Qt5.5.1开发,以Android 6.0.1设备为目标。
下面的示例代码可以粘贴到新的“QtQuick Controls Application”项目中。
的main.cpp
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include "contactshelper.h"
#include "contact.h"
#include "contact2.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
qmlRegisterType<ContactsHelper>("ContactsHelper",1,0,"ContactsHelper");
qRegisterMetaType<Contact>();
qmlRegisterType<Contact2>("ContactsHelper",1,0,"Contact");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
contact.h
#ifndef CONTACT_H
#define CONTACT_H
#include <QDebug>
#include <QMetaType>
class Contact {
Q_GADGET //!!!This macro was missing in the original question!!!
public:
Contact();
Contact(const Contact &other);
~Contact();
Q_PROPERTY(QString contactId MEMBER m_contactId)
Q_PROPERTY(QString displayLabel MEMBER m_displayLabel)
void setContactId(const QString contactId);
void setDisplayLabel(const QString displayLabel);
private:
QString m_contactId;
QString m_displayLabel;
};
Q_DECLARE_METATYPE(Contact)
#endif // CONTACT_H
contact.cpp
#include "contact.h"
#include <QDebug>
Contact::Contact(){}
Contact::~Contact(){}
Contact::Contact(const Contact &other) {
qDebug() << "Contact: copy constructor called: " << other.m_displayLabel;
m_contactId = other.m_contactId;
m_displayLabel = other.m_displayLabel;
}
void Contact::setContactId(const QString contactId) {
m_contactId = contactId;
}
void Contact::setDisplayLabel(const QString displayLabel) {
m_displayLabel = displayLabel;
}
contact2.h
#ifndef CONTACT2_H
#define CONTACT2_H
#include <QDebug>
#include <QObject>
class Contact2: public QObject
{
Q_OBJECT
public:
explicit Contact2(QObject *parent = 0);
~Contact2();
Q_PROPERTY(QString contactId MEMBER m_contactId)
Q_PROPERTY(QString displayLabel MEMBER m_displayLabel)
void setContactId(const QString contactId);
void setDisplayLabel(const QString displayLabel);
private:
QString m_contactId;
QString m_displayLabel;
};
#endif // CONTACT2_H
contact2.cpp
#include "contact2.h"
Contact2::Contact2(QObject *parent) : QObject(parent) {}
Contact2::~Contact2() {}
void Contact2::setContactId(const QString contactId) {
m_contactId = contactId;
}
void Contact2::setDisplayLabel(const QString displayLabel) {
m_displayLabel = displayLabel;
}
contactshelper.h
#ifndef CONTACTSHELPER_H
#define CONTACTSHELPER_H
#include "contact.h"
#include "contact2.h"
#include <QObject>
class ContactsHelper : public QObject {
Q_OBJECT
public:
explicit ContactsHelper(QObject *parent = 0);
Q_INVOKABLE void fakeContactFound();
Q_INVOKABLE void fakeContactFound2();
signals:
void contactFound(const int index, const int count, const Contact &contact);
void contactFound2(const int index, const int count, const Contact *contact);
};
#endif // CONTACTSHELPER_H
contactshelper.cpp
#include "contactshelper.h"
#include "contact.h"
ContactsHelper::ContactsHelper(QObject *parent) : QObject(parent) {}
void ContactsHelper::fakeContactFound() {
qDebug() << "ContactsHelper: faking contactFound";
Contact contact;
contact.setContactId("123");
contact.setDisplayLabel("Aunt Agatha");
contactFound(1, 1, contact);
}
void ContactsHelper::fakeContactFound2() {
qDebug() << "ContactsHelper: faking contactFound";
Contact2 *contact = new Contact2;
contact->setContactId("123");
contact->setDisplayLabel("Uncle Fred");
this->contactFound2(1, 1, contact);
}
main.qml
import QtQuick 2.5
import QtQuick.Controls 1.4
import ContactsHelper 1.0
ApplicationWindow {
visible: true
ContactsHelper {
id: contactsHelper
onContactFound: {
console.log ("QML: onContactFound signal received!");
console.log ("QML: displayLabel: " + contact.displayLabel);
listProperty(contact);
}
onContactFound2: {
console.log ("QML: onContactFound2 signal received!");
console.log ("QML: displayLabel: " + contact.displayLabel);
listProperty(contact);
}
function listProperty(item) {
console.log ("QML: listing contact properties ...");
for (var p in item)
console.log(p + ": " + item[p]);
}
}
MainForm {
anchors.fill: parent
button1.onClicked: {contactsHelper.fakeContactFound()}
button2.onClicked: {contactsHelper.fakeContactFound2()}
}
}
MainForm.ui.qml
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.2
Item {
width: 640
height: 480
property alias button1: button1
property alias button2: button2
RowLayout {
anchors.centerIn: parent
Button {
id: button1
text: qsTr("Fake contactFound")
}
Button {
id: button2
text: qsTr("Fake contactFound2")
}
}
}