# QObject

如介绍中所述,QObject是实现Qt核心功能(如信号和插槽)的关键。这是通过内省实现的,而QObject提供了内省。。 QObject是Qt中几乎所有类的基类。值类型是个例外,例如QColorQStringQList

Qt对象是标准的C++对象,但具有更多功能。这些功能可以分为两组:内省和内存管理。内省意味着Qt对象知道自己的类名、自己与其他类的关系,以及自己的方法和属性。内存管理概念意味着每个Qt对象都可以是子对象的父对象。父对象拥有子对象,当父对象被销毁时,它负责销毁其子对象。

了解QObject的能力是如何影响类的最佳方式是:使用Qt使能标准的C++类。下面显示的类代表一个这样的普通类。

Person类是具有名字、性别属性的数据类。 Person类使用Qt的对象系统向c++类中添加元信息。它允许Person对象的用户连接到槽并在属性更改时得到通知。

class Person : public QObject
{
    Q_OBJECT // 启用元对象能力 

    // QML所需的属性声明
    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(Gender gender READ gender WRITE setGender NOTIFY genderChanged)

    // 启用枚举自省
    Q_ENUMS(Gender)
    
    // 使得在QML里面可以创建这个类型
    QML_ELEMENT

public:
    // 带有父对象进行内存管理的标准Qt构造器
    Person(QObject *parent = 0);

    enum Gender { Unknown, Male, Female, Other };

    QString name() const;
    Gender gender() const;

public slots: // 可以被连接到信号的槽,或被调用
    void setName(const QString &);
    void setGender(Gender);

signals: // 可以被发射的信号
    void nameChanged(const QString &name);
    void genderChanged(Gender gender);

private:
    // 数据成员
    QString m_name;
    Gender m_gender;
};

构造函数将父对象传递给超类并初始化成员。Qt的值类型会自动初始化。在本例中,QString将初始化为空字符串(QString::isNull()),而成员gender将显式初始化为Person::Unknown

Person::Person(QObject *parent)
    : QObject(parent)
    , m_gender(Person::Unknown)
{
}

getter函数以属性命名,通常是一个简单的const函数。当属性发生更改时,setter会发出更改的信号。为了确保值实际上已经更改,插入了一个守护功能来比较当前值和新值。只有当值不同时,才将其分配给成员变量并发出更改的信号。

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

void Person::setName(const QString &name)
{
    if (m_name != name) // guard
    {
        m_name = name;
        emit nameChanged(m_name);
    }
}

有了一个从QObject派生的类,可以使用metaObject()方法探索获得更多的元对象能力。 例如,从对象中检索类名。

Person* person = new Person();
person->metaObject()->className(); // "Person"
Person::staticMetaObject.className(); // "Person"

QObject基类和元对象可以访问的更多功能,请查看QMetaObject文档。

提示

QObjectQ_OBJECT宏有一个轻量级的兄弟:Q_GADGET。可以将Q_GADGET宏插入到非QObject派生类的私有部分,以暴露其属性和可调用的方法。请注意,Q_GADGET对象不能有信号,因此属性不能提供被更改的通知信号。尽管如此,这对于从C++暴露到QML的数据结构提供类似于QML的接口还是很有用的,而无需消耗调用完全成熟的QObject的成本。

最后更新: 2/3/2022, 4:21:42 PM