• Qt5官方demo解析集30——Extending QML


    本系列全部文章能够在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873

    接上文Qt5官方demo解析集29——Extending QML - Property Value Source Example


    还记得我们以前在Qt5官方demo解析集17——Chapter 3: Adding Property Bindings一文中接触过QML自己定义类型的属性绑定吗?假设不记得了,能够移步进行了解。由于项目尺寸的原因,那个样例可能更好理解。

    这个样例也是我们Extending QML(扩展QML)系列的最后一个样例了,尽管相较前一个样例也仅仅有小小的修改。只是我们还是把整个project都完整的看一遍吧~



    binding.qrc中是我们的qml文件,它实例化了BirthdayParty类以及其全部的子对象。


    Person类建立了一个自己定义的QML类型,因为它并非一个可视化组件,且QML不论什么组件均基于Qt 的元对象系统,因此继承自QObject。

    接着定义了ShoeDescription用来对Person类的shoe属性进行描写叙述,使用特定的方法。我们在对shoe赋值时不须要实例化这个ShoeDescription组件。

    再定义两个Person的派生类Boy、Girl,能够用来对Person对象分类。


    person.h:

    #ifndef PERSON_H
    #define PERSON_H
    
    #include <QObject>
    #include <QColor>
    
    class ShoeDescription : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(int size READ size WRITE setSize NOTIFY shoeChanged)        // NOTIFY用在属性绑定,当该属性值发生改变时发出信号shoeChanged
        Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY shoeChanged)  // 通过该信号,我们就能使得被绑定的属性值随之发生改变
        Q_PROPERTY(QString brand READ brand WRITE setBrand NOTIFY shoeChanged)
        Q_PROPERTY(qreal price READ price WRITE setPrice NOTIFY shoeChanged)
    public:
        ShoeDescription(QObject *parent = 0);
    
        int size() const;
        void setSize(int);
    
        QColor color() const;
        void setColor(const QColor &);
    
        QString brand() const;
        void setBrand(const QString &);
    
        qreal price() const;
        void setPrice(qreal);
    signals:
        void shoeChanged();                      // 定义该shoeChanged()信号
    
    private:
        int m_size;
        QColor m_color;
        QString m_brand;
        qreal m_price;
    };
    
    class Person : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    // ![0]
        Q_PROPERTY(ShoeDescription *shoe READ shoe CONSTANT)
    // ![0]
    public:
        Person(QObject *parent = 0);
    
        QString name() const;
        void setName(const QString &);
    
        ShoeDescription *shoe();
    signals:
        void nameChanged();
    
    private:
        QString m_name;
        ShoeDescription m_shoe;
    };
    
    class Boy : public Person
    {
        Q_OBJECT
    public:
        Boy(QObject * parent = 0);
    };
    
    class Girl : public Person
    {
        Q_OBJECT
    public:
        Girl(QObject * parent = 0);
    };
    
    #endif // PERSON_H




    person.cpp:

    #include "person.h"
    
    ShoeDescription::ShoeDescription(QObject *parent)
    : QObject(parent), m_size(0), m_price(0)
    {
    }
    
    int ShoeDescription::size() const
    {
        return m_size;
    }
    
    void ShoeDescription::setSize(int s)
    {
        if (m_size == s)
            return;
    
        m_size = s;
        emit shoeChanged();                   // 该信号应该在该属性被正确写入后发出
    }
    
    QColor ShoeDescription::color() const
    {
        return m_color;
    }
    
    void ShoeDescription::setColor(const QColor &c)
    {
        if (m_color == c)
            return;
    
        m_color = c;
        emit shoeChanged();
    }
    
    QString ShoeDescription::brand() const
    {
        return m_brand;
    }
    
    void ShoeDescription::setBrand(const QString &b)
    {
        if (m_brand == b)
            return;
    
        m_brand = b;
        emit shoeChanged();
    }
    
    qreal ShoeDescription::price() const
    {
        return m_price;
    }
    
    void ShoeDescription::setPrice(qreal p)
    {
        if (m_price == p)
            return;
    
        m_price = p;
        emit shoeChanged();
    }
    
    Person::Person(QObject *parent)
    : QObject(parent)
    {
    }
    
    QString Person::name() const
    {
        return m_name;
    }
    
    void Person::setName(const QString &n)
    {
        if (m_name == n)
            return;
    
        m_name = n;
        emit nameChanged();
    }
    
    ShoeDescription *Person::shoe()
    {
        return &m_shoe;
    }
    
    
    Boy::Boy(QObject * parent)
    : Person(parent)
    {
    }
    
    
    Girl::Girl(QObject * parent)
    : Person(parent)
    {
    }


    接下来是我们的主类BirthdayParty,它也是example.qml中的根项目。它有一个以Person指针为參数的host属性,用来指明寿星;有一个以Person列表指针为參数guests属性,用来指明客人,而且该属性被设置为默认属性,这样在QML中没有指明属性的值将被划归它的名下。一个announcement属性,用来被动态改变以播放歌词。另外,该类还定义了一个partyStarted()信号,我们能够在QML中使用onPartyStarted 来响应该信号。


    此外,再定义一个BirthdayPartyAttached类。它用来为BirthdayParty提供一个附加属性。


    birthdayparty.h:

    #ifndef BIRTHDAYPARTY_H
    #define BIRTHDAYPARTY_H
    
    #include <QObject>
    #include <QDate>
    #include <QDebug>
    #include <qqml.h>
    #include "person.h"
    
    class BirthdayPartyAttached : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QDate rsvp READ rsvp WRITE setRsvp NOTIFY rsvpChanged)  // 该例中大多数属性均定义了属性绑定
    public:
        BirthdayPartyAttached(QObject *object);
    
        QDate rsvp() const;
        void setRsvp(const QDate &);
    
    signals:
        void rsvpChanged();
    
    private:
        QDate m_rsvp;
    };
    
    class BirthdayParty : public QObject
    {
        Q_OBJECT
    // ![0]
        Q_PROPERTY(Person *host READ host WRITE setHost NOTIFY hostChanged)
    // ![0]
        Q_PROPERTY(QQmlListProperty<Person> guests READ guests)
        Q_PROPERTY(QString announcement READ announcement WRITE setAnnouncement)
        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;
    
        QString announcement() const;
        void setAnnouncement(const QString &);
    
        static BirthdayPartyAttached *qmlAttachedProperties(QObject *);
    
        void startParty();
    signals:
        void partyStarted(const QTime &time);
        void hostChanged();
    
    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)
    {
        if (d != m_rsvp) {
            m_rsvp = d;
            emit rsvpChanged();
        }
    }
    
    
    BirthdayParty::BirthdayParty(QObject *parent)
    : QObject(parent), m_host(0)
    {
    }
    
    Person *BirthdayParty::host() const
    {
        return m_host;
    }
    
    void BirthdayParty::setHost(Person *c)
    {
        if (c == m_host) return;
        m_host = c;
        emit hostChanged();
    }
    
    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);
    }
    
    QString BirthdayParty::announcement() const
    {
        return QString();
    }
    
    void BirthdayParty::setAnnouncement(const QString &speak)
    {
        qWarning() << qPrintable(speak);
    }
    
    BirthdayPartyAttached *BirthdayParty::qmlAttachedProperties(QObject *object)
    {
        return new BirthdayPartyAttached(object);
    }



    在该系列第9个样例中,我们接触到了HappyBirthdaySong类,它是一个自己定义的Property Value Source,用来为QML属性提供随时间变化的能力,类似于Animation。在该样例中,它被用于announcement属性。

    happybirthdaysong.h:

    #ifndef HAPPYBIRTHDAYSONG_H
    #define HAPPYBIRTHDAYSONG_H
    
    #include <QQmlPropertyValueSource>
    #include <QQmlProperty>
    
    #include <QStringList>
    
    class HappyBirthdaySong : public QObject, public QQmlPropertyValueSource
    {
        Q_OBJECT
        Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
        Q_INTERFACES(QQmlPropertyValueSource)
    public:
        HappyBirthdaySong(QObject *parent = 0);
    
        virtual void setTarget(const QQmlProperty &);
    
        QString name() const;
        void setName(const QString &);
    
    private slots:
        void advance();
    
    signals:
        void nameChanged();
    private:
        int m_line;
        QStringList m_lyrics;
        QQmlProperty m_target;
        QString m_name;
    };
    
    #endif // HAPPYBIRTHDAYSONG_H


    happybirthdaysong.cpp:

    #include "happybirthdaysong.h"
    #include <QTimer>
    
    HappyBirthdaySong::HappyBirthdaySong(QObject *parent)
    : QObject(parent), m_line(-1)
    {
        setName(QString());
        QTimer *timer = new QTimer(this);
        QObject::connect(timer, SIGNAL(timeout()), this, SLOT(advance()));
        timer->start(1000);
    }
    
    void HappyBirthdaySong::setTarget(const QQmlProperty &p)
    {
        m_target = p;
    }
    
    QString HappyBirthdaySong::name() const
    {
        return m_name;
    }
    
    void HappyBirthdaySong::setName(const QString &name)
    {
        if (m_name == name)
            return;
    
        m_name = name;
    
        m_lyrics.clear();
        m_lyrics << "Happy birthday to you,";
        m_lyrics << "Happy birthday to you,";
        m_lyrics << "Happy birthday dear " + m_name + ",";
        m_lyrics << "Happy birthday to you!";
        m_lyrics << "";
        
        emit nameChanged();
    }
        
    void HappyBirthdaySong::advance()
    {
        m_line = (m_line + 1) % m_lyrics.count();
    
        m_target.write(m_lyrics.at(m_line));
    }
    

    在main.cpp中将这些C++类注冊成QML类型后。我们就能够在QML中创建一个实例化的BirthdayParty,并对其属性赋值:

    example.qml:

    import People 1.0
    import QtQuick 2.0  // For QColor
    
    // ![0]
    BirthdayParty {
        id: theParty
    
        HappyBirthdaySong on announcement { name: theParty.host.name }      // 属性绑定
    
        host: Boy {
            name: "Bob Jones"
            shoe { size: 12; color: "white"; brand: "Nike"; price: 90.0 }
        }
    // ![0]
        onPartyStarted: console.log("This party started rockin' at " + time);
    
    
        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 "happybirthdaysong.h"
    #include "person.h"
    
    int main(int argc, char ** argv)
    {
        QCoreApplication app(argc, argv);
        qmlRegisterType<BirthdayPartyAttached>();
        qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
        qmlRegisterType<HappyBirthdaySong>("People", 1,0, "HappyBirthdaySong");
        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());
            }
    
            party->startParty();
        } else {
            qWarning() << component.errors();
        }
    
        return app.exec();
    }

    输出例如以下:


  • 相关阅读:
    GUIX 创建工程注意事项
    VS 中bool和BOOL的区别
    git 在Windows上的应用
    rt-thread 相关网站地址
    tcp client
    VS2015 下载地址
    软件各种协议比较(GPL、AGPL、LGPL、Apache、Zlib/Libpng、BSD、MIT)
    UILabel标签
    UIbutton
    数据互转
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6835771.html
Copyright © 2020-2023  润新知