首页 > 代码库 > Qt5官方demo解析集28——Extending QML - Signal Support Example

Qt5官方demo解析集28——Extending QML - Signal Support Example

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873

接上文Qt5官方demo解析集27——Extending QML - Attached Properties Example


这个demo演示了为QML自定义类型添加信号的方法,这与Qt5官方demo解析集16——Chapter 2: Connecting to C++ Methods and Signals所介绍的差不多,鉴于例子的尺寸,可能那一篇要更清晰一些。


无论如何,我们还是要继续扩展这个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;
}

结果如图: