Qt QML referenceexamples attached Demo hacking

/*********************************************************************************************
 *                       Qt QML referenceexamples attached Demo hacking
 *  说明:
 *      1. 本源代码来自Qt自带的Example,而本文也仅仅是代码解读,需要有点基础;
 *      2. 由于是Qt自带Demo,分为几个文件,文件存在联系,而本人把所有代码放在这个文件里,会照成阅读困难;
 *      3. 由于2中的原因,请尽量在Qt中阅读源程序;
 *      4. 强烈建议您使用Qt中的FakeVim进行代码阅读,当然这也只是个建议;  :)
 *
 *                                  2015-5-17 深圳 晴 南山平山村 曾剑锋
 ********************************************************************************************/

                             \\\\\\\\\-*- 目录 -*-/////////
                             |  一、main.cpp
                             |  二、person.h
                             |  三、person.c
                             |  四、birthdayparty.h
                             |  五、birthdayparty.cpp
                             |  六、example.qml
                             \\\\\\\\\\\\\\\//////////////

一、main.cpp
    #include <QCoreApplication>
    #include <QQmlEngine>
    #include <QQmlComponent>
    #include <QDebug>
    #include "birthdayparty.h"
    #include "person.h"

    int main(int argc, char ** argv)
    {
        /**
         * The QApplication class manages the GUI application's control flow and main settings.
         *     初始化并配置GUI界面环境
         */
        QCoreApplication app(argc, argv);

        /**
         * This template function registers the C++ type in the QML system with the name qmlName,
         * in the library imported from uri having the version number composed from versionMajor
         * and versionMinor.
         *
         * For example, this registers a C++ class MySliderItem as a QML type named Slider for
         * version 1.0 of a type namespace called "com.mycompany.qmlcomponents":
         *     qmlRegisterType<MySliderItem>("com.mycompany.qmlcomponents", 1, 0, "Slider");
         *
         * qmlRegisterType<Person>("People", 1,0, "Person"):
         *     1. qmlRegisterType是用来向QML系统注册C++类型的;
         *     2. 这里相当于向QML系统注册了一个Person 1.0 版本的类;
         *     3. 指定了命名空间为Person,所以在qml文件中需要用import People 1.0,引入命名空间,
         *         当然这里也制定了版本号;
         *   参数说明j:
         *     1. 泛型<Person>代表要注册进QML系统C++类;
         *     2. 第一个参数是需要创建的QML命名空间;
         *     3. 第二、三个参数是对应的QML类型的版本号;
         *     4. 第四个参数是C++类对应的QML类型的名字;
         *
         * 如果注释掉这一行会出现以下错误,编译运行时错误结果:
         *     QQmlComponent: Component is not ready
         *     (qrc:example.qml:42:1: module "People" is not installed)
         *
         */
        qmlRegisterType<BirthdayPartyAttached>();
        qmlRegisterType<BirthdayParty>("People", 1,0, "BirthdayParty");
        qmlRegisterType<ShoeDescription>();
        qmlRegisterType<Person>();
        qmlRegisterType<Boy>("People", 1,0, "Boy");
        qmlRegisterType<Girl>("People", 1,0, "Girl");

        /**
         * QQmlApplicationEngine provides a convenient way to load an application from a single QML file.
         *     创建QML引擎(engine)
         */
        QQmlEngine engine;      //QML引擎
        /**
         * The QQmlComponent class encapsulates a QML component definition Components are reusable,
         * encapsulated QML types with well-defined interfaces.
         *     个人理解就是加载QML文件的意思,利用component.create()创建对象
         */
        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!";         //console output

            /**
             * Returns the given object cast to type T if the object is of type T (or of a subclass);
             * otherwise returns 0. If object is 0 then it will also return 0.
             *     这里相当于类型判断的意思
             */
            if (qobject_cast<Boy *>(party->host()))
                qWarning() << "He is inviting:";
            else
                qWarning() << "She is inviting:";

            /**
             * 这是我自己添加的测试代码,主要用于测试example.qml中的BirthdayParty.rsvp: "2015-05-16"可否写
             * 在 BirthdayParty {}里面,测试结果:不一定要写在 Boy {}里面,可以写在任何地方。
             */
            /**
             * qmlAttachedPropertiesObject: This returns the attached object instance that has been
             * attached to the specified attachee by the attaching type T.
             */
            QObject *attached_out = qmlAttachedPropertiesObject<BirthdayParty>(party, false);
            QDate rsvpDate_out;
            if (attached_out)
                rsvpDate_out = attached_out->property("rsvp").toDate();
            qWarning() << " zjf  " << "RSVP date:" << qPrintable(rsvpDate_out.toString());

            for (int ii = 0; ii < party->guestCount(); ++ii) {
                Person *guest = party->guest(ii);

                //! [query rsvp]
                QDate rsvpDate;
                /**
                 * This returns the attached object instance that has been attached to the
                 * specified attachee by the attaching type T.
                 */
                QObject *attached = qmlAttachedPropertiesObject<BirthdayParty>(guest, false);

                if (attached)
                    rsvpDate = attached->property("rsvp").toDate();
                //! [query rsvp]
                if (rsvpDate.isNull())
                    qWarning() << "   " << guest->name() << "RSVP date: Hasn't RSVP'd";
                else
                    qWarning() << "   " << guest->name() << "RSVP date:" << qPrintable(rsvpDate.toString());
            }

        } else {
            qWarning() << component.errors();
        }

        /**
         * QStringLiteral: Creating a QString from it is free in this case, and the generated string data
         *     is stored in the read-only segment of the compiled object file.
         *     这是一个宏,用于创建一个字符串,该字符串存放在自读数据区
         * QUrl: The most common way to use QUrl is to initialize it via the constructor by passing a QString.
         *        Otherwise, setUrl() can also be used.
         *     最常用于初始化一个QUrl的是给其构造函数传一个字符串,此外也可以使用setUrl()
         * engine.load: Loads the root QML file located at filePath:.
         *     加载用QML引擎加载要显示的界面
         */
        //engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

        /**
         * Enters the main event loop and waits until exit() is called.
         *     进入主事件循环,并等待直到exit()函数被调用
         */
        //return app.exec();

        return 0;
    }

二、person.h
    #ifndef PERSON_H
    #define PERSON_H

    #include <QObject>
    #include <QColor>

    class ShoeDescription : public QObject
    {
        /**
         * The Q_OBJECT macro must appear in the private section of a class definition
         * that declares its own signals and slots or that uses other services provided
         * by Qt's meta-object system.
         *     Q_OBJECT宏应该使用在一个类定义时的私有段,其声明了一些信号和槽
         */
        Q_OBJECT

        /**
         * The Property System:
         * To declare a property, use the Q_PROPERTY() macro in a class that inherits QObject.
         *     Q_PROPERTY(type name
         *         (READ getFunction [WRITE setFunction] |
         *          MEMBER memberName [(READ getFunction | WRITE setFunction)])
         *         [RESET resetFunction]
         *         [NOTIFY notifySignal]
         *         [REVISION int]
         *         [DESIGNABLE bool]
         *         [SCRIPTABLE bool]
         *         [STORED bool]
         *         [USER bool]
         *         [CONSTANT]
         *         [FINAL])
         *     这里采用宏的形式来对变量进行声明定义,由于class默认是私有属性,所以这里我们无法直接
         *     访问name、shoeSize,要通过其READ、WRITE函数来进行访问(access)
         */
        Q_PROPERTY(int size READ size WRITE setSize)
        Q_PROPERTY(QColor color READ color WRITE setColor)
        Q_PROPERTY(QString brand READ brand WRITE setBrand)
        Q_PROPERTY(qreal price READ price WRITE setPrice)
    public:
        ShoeDescription(QObject *parent = 0);  //默认构造函数

        /**
         * 接下来是一些READ、WRITE函数的声明
         */
        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);
    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)
        Q_PROPERTY(ShoeDescription *shoe READ shoe)
    public:
        Person(QObject *parent = 0);

        QString name() const;
        void setName(const QString &);

        ShoeDescription *shoe();
    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.c
    #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)
    {
        m_size = s;
    }

    QColor ShoeDescription::color() const
    {
        return m_color;
    }

    void ShoeDescription::setColor(const QColor &c)
    {
        m_color = c;
    }

    QString ShoeDescription::brand() const
    {
        return m_brand;
    }

    void ShoeDescription::setBrand(const QString &b)
    {
        m_brand = b;
    }

    qreal ShoeDescription::price() const
    {
        return m_price;
    }

    void ShoeDescription::setPrice(qreal p)
    {
        m_price = p;
    }

    Person::Person(QObject *parent)
    : QObject(parent)
    {
    }

    QString Person::name() const
    {
        return m_name;
    }

    void Person::setName(const QString &n)
    {
        m_name = n;
    }

    ShoeDescription *Person::shoe()
    {
        return &m_shoe;
    }

    Boy::Boy(QObject * parent)
    : Person(parent)
    {
    }

    Girl::Girl(QObject * parent)
    : Person(parent)
    {
    }

四、birthdayparty.h
    #ifndef BIRTHDAYPARTY_H
    #define BIRTHDAYPARTY_H

    #include <QObject>
    #include <QDate>
    #include <qqml.h>
    #include "person.h"

    // 这一部分内容基本已经在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)

        /**
         * For QMap, QList, and QValueList properties, the property value is a QVariant whose
         * value is the entire list or map. Note that the Q_PROPERTY string cannot contain
         * commas, because commas separate macro arguments. Therefore, you must use QMap as
         * the property type instead of QMap<QString,QVariant>. For consistency, also use
         * QList and QValueList instead of QList<QVariant> and QValueList<QVariant>.
         *
         *     请注意这种写法,
         */
        Q_PROPERTY(QQmlListProperty<Person> guests READ guests)

        /**
         * Any QObject-derived type that is registered as an instantiable QML object type
         * can optionally specify a default property for the type. A default property is
         * the property to which an object's children are automatically assigned if they
         * are not assigned to any specific property.
         *
         * The default property can be set by calling the Q_CLASSINFO() macro for a class
         * with a specific "DefaultProperty" value. For example, the MessageBoard class below
         * specifies its messages property as the default property for the class:
         *
         *     将属性guests设为默认属性,这样在QML文件中就可以简写了
         */
        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 attached]
        /**
         * The mechanisms for providing attached objects can be implemented from C++ by
         * providing classes for the attached object type and attaching type. For the
         * attached object type, provide a QObject-derived class that defines the attributes
         * to be made accessible to attachee objects. For the attaching type, provide a
         * QObject-derived class that.
         *
         * implements a static qmlAttachedProperties() with the following signature:
         */
        static BirthdayPartyAttached *qmlAttachedProperties(QObject *);
        //! [static attached]
    private:
        Person *m_host;
        QList<Person *> m_guests;
    };

    //! [declare attached]
    /**
     * Declares additional properties of the given Type as described by the specified Flags.
     * Current the only supported type info is QML_HAS_ATTACHED_PROPERTIES which declares
     * that the Type supports attached properties.
     *
     * 这里感觉是告诉系统BirthdayParty类附属性,根据example.qml文件里里的写法,
     * 附属性写法为BirthdayParty.rsvp
     */
    QML_DECLARE_TYPEINFO(BirthdayParty, QML_HAS_ATTACHED_PROPERTIES)
    //! [declare attached]
    #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);
    }

    /**
     * 实现了attached需要的函数
     */
    BirthdayPartyAttached *BirthdayParty::qmlAttachedProperties(QObject *object)
    {
        return new BirthdayPartyAttached(object);
    }

六、example.qml
    import People 1.0
    import QtQuick 2.0  // For QColor

    //! [begin]
    BirthdayParty {
    //! [begin]

    //! [rsvp]
        Boy {
            name: "Robert Campbell"
            /**
             * 这里为什么是这样实现,目前还不是很清楚,但经过测试发现,貌似这就是attach的的意思。
             * 另外个人从BirthdayParty.rsvp代表BirthdayParty的附加属性rsvp.
             */
            BirthdayParty.rsvp: "2009-07-01"
        }
    //! [rsvp]
        // ![1]
        Boy {
            name: "Leo Hodges"
            shoe { size: 10; color: "black"; brand: "Reebok"; price: 59.95 }

            BirthdayParty.rsvp: "2009-07-06"
        }
        // ![1]
        host: Boy {
            name: "Jack Smith"
            shoe { size: 8; color: "blue"; brand: "Puma"; price: 19.95 }
        }

        /**
         * 本人自己添加的额外的代码,用于测试附加属性是否可以放在这里,相当于测试作用域的样子
         */
        BirthdayParty.rsvp: "2015-05-16"
    //! [end]
    }
    //! [end]

 

时间: 2024-10-31 04:01:58

Qt QML referenceexamples attached Demo hacking的相关文章

Qt qml中listview 列表视图控件(下拉刷新、上拉分页、滚动轴)_Android

Qt qml listview下拉刷新和上拉分页主要根据contentY来判断.但要加上顶部下拉指示器.滚动条,并封装成可简单调用的组件,着实花了我不少精力:) 先给大家展示下效果图: [功能] 下拉刷新和上拉分页逻辑 /下拉刷新 /上拉更多 /滚动栏 /工具栏半拉显隐 Author: surfsky.cnblogs.com Lisence: MIT 请保留此文档声明 History: init. surfsky.cnblogs.com, 2015-01 add initPosition pro

linux SPI bus demo hacking

/********************************************************************** * linux SPI bus demo hacking * 说明: * 本文主要解析linux应用程序如何使用SPI总线和设备通信. * * 2016-3-28 深圳 南山平山村 曾剑锋 *********************************************************************/ // 参考文档: //

linux watchdog demo hacking

/********************************************************************** * linux watchdog demo hacking * 说明: * 本文主要解析linux watchdog大概应该如何操作. * * 2016-3-28 深圳 南山平山村 曾剑锋 *********************************************************************/ #include <st

Linux SocketCan client server demo hacking

/*********************************************************************** * Linux SocketCan client server demo hacking * 说明: * 本文主要是解读Linux上的SocketCan的基本使用方法,内容和Linux上的 * 网络编程差不多. * * 2016-3-28 深圳 南山平山村 曾剑锋 ********************************************

Qt 获取usb设备信息 hacking

/************************************************************************** * Qt 获取usb设备信息 hacking * 声明: * 本文主要是为了查看之前朋友留下的Qt获取usb设备信息软件运作机制. * * 2015-12-31 深圳 南山平山村 曾剑锋 *************************************************************************/ 一.usb

下一代 Ubuntu 桌面将基于 Qt 和 QML

Ubuntu 宣布将使用其自己开发的名为 Mir 的显示服务器,用来替换 X Windows Server.更换的原因 Ubuntu 的说法是: 没有一个现有的解决方案能够在不需要采取重大妥协的情况下实现我们对用户体验和质量提升的愿景. 此外 Ubuntu 宣布将移植 Unity 桌面到基于 Qt/QML 技术,使用 Mir 后端服务器,以便开发者更高效的开发.

QML运行环境

简述 QML 文档由 QML 运行环境加载和执行.这包括 Declarative UI 引擎以及内置的 QML 类型和插件模块,并且它还提供了对第三方 QML 类型和模块的访问. 使用 QML 的应用程序,需要调用 QML 运行环境才能执行 QML 文档.这可以通过创建 QQuickView 或 QQmlEngine 来完成.此外,Declarative UI 包包含了 qmlscene 工具,用于加载 .qml 文件.此工具对于开发和测试 QML 代码非常有用,无需编写 C++ 应用程序即可加

【Qt编程】基于Qt的词典开发系列&amp;lt;十四&amp;gt;自动补全功能

    最近写了一个查单词的类似有道词典的软件,里面就有一个自动补全功能(即当你输入一个字母时,就会出现几个候选项).这个自动补全功能十分常见,百度搜索关键词时就会出现.不过它们这些补全功能都是与你输入的进行首字匹配,有时也会不方便.例如,如果我输入一个"好",如果是首字匹配的话会出现下图: 如果是句中匹配的话,则是这种情况: 你可以根据自己的要求进行选择哪一种模式.     Qt中自带QCompleter类来实现上面的自动补全功能,读者可以在Qt自带的demo中很容易的学会该类的使用

QML使用资源系统

简述 Qt 资源系统允许将资源文件作为二进制文件存储在可执行文件中,这在构建混合的 QML/C++ 应用程序时非常有用,因为它通过资源系统的 URI 方案引用 QML 文件(以及其他资源,例如:图片和声音文件),而不是文件系统资源的相对路径或绝对路径. 简述 使用资源系统 实际应用 版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820 使用资源系统 要在混合的 QML/C++ 应用程序中使用资源系统: 创建一个 .qrc 资源集合文件(以