本系列全部文章能够在这里查看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="">

最新文章

  1. My Code Snippet
  2. form v
  3. LeetCode &quot;Longest Substring with At Most K Distinct Characters&quot;
  4. 如何写出性能好的sql
  5. gulp备忘
  6. Vboxmanage改动uuid报错的解决的方法
  7. [Swift]LeetCode854. 相似度为 K 的字符串 | K-Similar Strings
  8. vue style标签中使用less
  9. windows搭建zabbix agent
  10. Realm 简介
  11. HDU4662(SummerTrainingDay03-B)
  12. 数字IC设计入门书单
  13. 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.错误
  14. e815. 监听当前选择的的菜单或菜单项
  15. Effective JavaScript Item 35 使用闭包来保存私有数据
  16. docker——libnetwork插件网络功能
  17. Cobbler无人值守安装linux系统
  18. JavaScript权威指南第01章 JavaScript 概述
  19. 团队介绍 you i
  20. delphi实现窗体组建随窗体大小改变而改变

热门文章

  1. JavaScript 基础:Babel 转译 class 过程窥探
  2. perl中foreach(一)
  3. 【php】【运算符】位移运算符
  4. initcall机制
  5. Ubuntu 16.04如何使用无线网卡上网
  6. python基础学习笔记——迭代器
  7. Java单例模式简单实现
  8. luogu2051 [AHOI2009]中国象棋
  9. WCF学习-协议绑定
  10. 13-数组的API方法遍历