简要源码分析Q_PROPERTY

本文不打算像文档一样翻译Q_PROPERTY,而是从源码的角度来看看怎么使用Q_PROPERTY

QT的PROPERTY官方的定义,为了保持格式,我特地截屏,如下

毫无疑问, QT的moc系统对Q_PROPERTY有特别的处理,我们现在看看他处理了什么.
首先,定义一个类Test,代码如下:

class Test : public QObject
{
    Q_OBJECT
public:
    explicit Test(QObject *parent = 0);
    ~Test();
};

QT的moc会自动生成moc_test.cpp,备份一下这个文件
然后,加上一个属性描述:Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
对比官方的定义,我标识一下,看得更清楚

增加Q_PROPERTY后,的代码如下,只增加了一行代码:

class Test : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
public:
    explicit Test(QObject *parent = 0);
    ~Test();
};

重新编译,由于我们没有实现函数isEnabled和setEnabled,所以是编译不过的,出现如下错误信息:

但这说明moc已经工作了,并且生成了额外的代码,我们和刚刚没有加Q_PROPERTY的代码对比一下看看:

由上图可以看出,增加了一些properties的标识,增加了字符串"bool"和"enabled"
并且qt_metacall里增加了一些函数调用,如下图:

从图中我们可以看出,我们必须要自己实现函数isEnabled和setEnabled,否则别想编译过.
那好,增加这两个函数的实现代码

class Test : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
public:
    explicit Test(QObject *parent = 0);
    ~Test();

    void setEnabled(bool e) { m_bEnable = e; }
    bool isEnabled() const { return m_bEnable; }

private:
    bool m_bEnable;
};

我们实现了setEnabled和isEnabled,
然而,你可能会反问,这不就是个属性嘛,为了防止直接访问内部变量,我也经常写这样的代码啊.这样写的好处是保护成员变量不被意外修改.
然而,我想说的是,QT属性系统的精髓在于,可以用QObject的方法来访问继承类的属性.
还记得前面吗,增加了字符串"bool"和"enabled"
来,我们看看如何用基类来访问属性.

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    Test t;
    QObject *p = &t;

    qDebug() << t.isEnabled() << endl;
    qDebug() << p->property("enabled").toBool() << endl;

    p->setProperty("enabled", true);

    qDebug() << t.isEnabled() << endl;
    qDebug() << p->property("enabled").toBool() << endl;


    return a.exec();
}

运行结果为:
false
false
true
true

这就充分说明了,如何使用QObject的设置和访问属性

=======================   另一个例子的分割线   ======================

接下来再看一个QT文档中的例子,分析手法和上面一样
首先,来个最简单的,类定义如下:

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = 0);
    ~MyClass();
};

备份自动生成的moc_myclass.cpp
增加一个enum,并指明是Q_ENUMS

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = 0);
    ~MyClass();

    enum Priority {High, Low, VeryHigh, VeryLow};
    Q_ENUMS(Priority)
};

看下对比,enum增加了哪些东西

可以看出,增加了enum的一些东西,还增加了字符串"Priority", "High", "Low", "VeryHigh", "VeryLow"
接着,增加一行属性定义
Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
为了方便查看,我还是标识出来

增加后代码如下(由于我们增加了NOTIFY,所以还要增加一个signal priorityChanged, 不然moc编译不过):

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
public:
    explicit MyClass(QObject *parent = 0);
    ~MyClass();

    enum Priority {High, Low, VeryHigh, VeryLow};
    Q_ENUMS(Priority)
signals:
    void priorityChanged(Priority);

};

对比一下:

增加了字符串"priorityChanged(Priority)"
注意,增加字符串"priority",这个字符串是用来描述属性priority Q_PROPERTY(Priority priority ...)
继续比较

和上面分析Test类一样,不同点在于现在这个类增加了一个signal

好了,我们把类实现完全,增加函数setPriority和priority

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
public:
    explicit MyClass(QObject *parent = 0);
    ~MyClass();

    enum Priority {High, Low, VeryHigh, VeryLow};
    Q_ENUMS(Priority)
signals:
    void priorityChanged(Priority);

public:
    void setPriority(Priority priority)
    {
        m_priority = priority;
        emit priorityChanged(priority);
    }
    Priority priority() const
    { return m_priority; }

private:
    Priority m_priority;
};

然后,我们用同样的手法,写一个调用测试

    MyClass *myinstance = new MyClass;
    QObject *object = myinstance;

    object->setProperty("priority", "VeryHigh");
    qDebug() << object->property("priority").toUInt() << endl;


    delete myinstance;

打印输出
2
2在enum Priority {High, Low, VeryHigh, VeryLow}中就表示VeryHigh

总结:
QT的属性系统为我们提供了在基类访问子类的属性的方法,非常NICE.

参考:
https://doc.qt.io/qt-5/properties.html
https://blog.csdn.net/wzs250969969/article/details/78418124

代码: http://q1024.com/files/qt_window-master.zip 000200目录

posted @ 2022-09-08 08:09  xingzaicpp  阅读(251)  评论(0编辑  收藏  举报