本系列所有文章可以在这里查看[http://blog.csdn.net/cloud_castle/article/category/2123873](http://blog.csdn.net/cloud_castle/article/category/2123873) 接上文[Qt5官方demo解析集27——Extending QML - Attached Properties Example](http://blog.csdn.net/cloud_castle/article/details/37510123) 这个demo演示了为QML自定义类型添加信号的方法,这与[Qt5官方demo解析集16——Chapter 2: Connecting to C++ Methods and Signals](http://blog.csdn.net/cloud_castle/article/details/36882625)所介绍的差不多,鉴于例子的尺寸,可能那一篇要更清晰一些。 无论如何,我们还是要继续扩展这个BirthdayParty例程。我们为这个生日派对添加了一个“派对开始”的信号,并定义了一个函数用来发射这个信号。 由于person类依然没有改变,我们看看小小改动了的birthdayparty.h: ~~~ #ifndef BIRTHDAYPARTY_H #define BIRTHDAYPARTY_H #include <QObject> #include <QDate> #include <qqml.h> #include "person.h" class BirthdayPartyAttached : public QObject { Q_OBJECT Q_PROPERTY(QDate rsvp READ rsvp WRITE setRsvp) public: BirthdayPartyAttached(QObject *object); QDate rsvp() const; void setRsvp(const QDate &); private: QDate m_rsvp; }; class BirthdayParty : public QObject { Q_OBJECT Q_PROPERTY(Person *host READ host WRITE setHost) Q_PROPERTY(QQmlListProperty<Person> guests READ guests) Q_CLASSINFO("DefaultProperty", "guests") public: BirthdayParty(QObject *parent = 0); Person *host() const; void setHost(Person *); QQmlListProperty<Person> guests(); int guestCount() const; Person *guest(int) const; static BirthdayPartyAttached *qmlAttachedProperties(QObject *); void startParty(); // 自定义函数,之所以不使用Q_INVOKABLE是因为该函数是在main.cpp而不是QML中被调用的 // ![0] signals: void partyStarted(const QTime &time); // 自定义信号 // ![0] private: Person *m_host; QList<Person *> m_guests; }; QML_DECLARE_TYPEINFO(BirthdayParty, QML_HAS_ATTACHED_PROPERTIES) #endif // BIRTHDAYPARTY_H ~~~ birthdayParty.cpp: ~~~ #include "birthdayparty.h" BirthdayPartyAttached::BirthdayPartyAttached(QObject *object) : QObject(object) { } QDate BirthdayPartyAttached::rsvp() const { return m_rsvp; } void BirthdayPartyAttached::setRsvp(const QDate &d) { m_rsvp = d; } BirthdayParty::BirthdayParty(QObject *parent) : QObject(parent), m_host(0) { } Person *BirthdayParty::host() const { return m_host; } void BirthdayParty::setHost(Person *c) { m_host = c; } QQmlListProperty<Person> BirthdayParty::guests() { return QQmlListProperty<Person>(this, m_guests); } int BirthdayParty::guestCount() const { return m_guests.count(); } Person *BirthdayParty::guest(int index) const { return m_guests.at(index); } void BirthdayParty::startParty() // 该函数用来将当前时间作为信号参数发射出去 { QTime time = QTime::currentTime(); emit partyStarted(time); } BirthdayPartyAttached *BirthdayParty::qmlAttachedProperties(QObject *object) { return new BirthdayPartyAttached(object); } ~~~ example.qml: ~~~ import People 1.0 import QtQuick 2.0 // For QColor BirthdayParty { // ![0] onPartyStarted: console.log("This party started rockin' at " + time); // 在QML中我们不需要额外对信号进行处理 // ![0] // 只需要关注与该信号对应的onXXX函数 // 当信号发出时该函数即被执行 host: Boy { name: "Bob Jones" shoe { size: 12; color: "white"; brand: "Nike"; price: 90.0 } } Boy { name: "Leo Hodges" BirthdayParty.rsvp: "2009-07-06" shoe { size: 10; color: "black"; brand: "Reebok"; price: 59.95 } } Boy { name: "Jack Smith" shoe { size: 8; color: "blue"; brand: "Puma"; price: 19.95 } } Girl { name: "Anne Brown" BirthdayParty.rsvp: "2009-07-01" shoe.size: 7 shoe.color: "red" shoe.brand: "Marc Jacobs" shoe.price: 699.99 } // ![1] } // ![1] ~~~ main.cpp: ~~~ #include <QCoreApplication> #include <QQmlEngine> #include <QQmlComponent> #include <QDebug> #include "birthdayparty.h" #include "person.h" int main(int argc, char ** argv) { QCoreApplication app(argc, argv); qmlRegisterType<BirthdayPartyAttached>(); qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty"); qmlRegisterType<ShoeDescription>(); qmlRegisterType<Person>(); qmlRegisterType<Boy>("People", 1,0, "Boy"); qmlRegisterType<Girl>("People", 1,0, "Girl"); QQmlEngine engine; QQmlComponent component(&engine, QUrl("qrc:example.qml")); BirthdayParty *party = qobject_cast<BirthdayParty *>(component.create()); if (party && party->host()) { qWarning() << party->host()->name() << "is having a birthday!"; if (qobject_cast<Boy *>(party->host())) qWarning() << "He is inviting:"; else qWarning() << "She is inviting:"; for (int ii = 0; ii < party->guestCount(); ++ii) { Person *guest = party->guest(ii); QDate rsvpDate; QObject *attached = qmlAttachedPropertiesObject<BirthdayParty>(guest, false); if (attached) rsvpDate = attached->property("rsvp").toDate(); if (rsvpDate.isNull()) qWarning() << " " << guest->name() << "RSVP date: Hasn't RSVP'd"; else qWarning() << " " << guest->name() << "RSVP date:" << qPrintable(rsvpDate.toString()); // 上文讨论了qPrintable的问题 } party->startParty(); // 这里调用了发射信号函数,因此party开始时间将被打印在最后一行 } else { qWarning() << component.errors(); } return 0; } ~~~ 结果如图: ![](https://box.kancloud.cn/2016-01-18_569cbd08baf81.jpg)