Qt5官方demo解析集30——Extending QML - Binding Example
本系列全部文章能够在这里查看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();
}
输出例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2xvdWRfY2FzdGxl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
最新文章
- My Code Snippet
- form v
- LeetCode ";Longest Substring with At Most K Distinct Characters";
- 如何写出性能好的sql
- gulp备忘
- Vboxmanage改动uuid报错的解决的方法
- [Swift]LeetCode854. 相似度为 K 的字符串 | K-Similar Strings
- vue style标签中使用less
- windows搭建zabbix agent
- Realm 简介
- HDU4662(SummerTrainingDay03-B)
- 数字IC设计入门书单
- hive sequencefile导入文件遇到FAILED: SemanticException Unable to load data to destination table. Error: The file that you are trying to load does not match the file format of the destination table.错误
- e815. 监听当前选择的的菜单或菜单项
- Effective JavaScript Item 35 使用闭包来保存私有数据
- docker——libnetwork插件网络功能
- Cobbler无人值守安装linux系统
- JavaScript权威指南第01章 JavaScript 概述
- 团队介绍 you i
- delphi实现窗体组建随窗体大小改变而改变