• 解析Qt元对象系统(四) 属性系统(确实比较方便)


    官方解释

    我们在Qt源码中可以看到一个QObject的子类经常会用到一些Q_开头的宏,例如QMainWindow类开始部分代码是这样的:

    Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
    Q_PROPERTY(Qt::ToolButtonStyle toolButtonStyle READ toolButtonStyle WRITE setToolButtonStyle)
    ......
    public:
    enum DockOption {
    AnimatedDocks = 0x01,
    AllowNestedDocks = 0x02,
    AllowTabbedDocks = 0x04,
    ForceTabbedDocks = 0x08, // implies AllowTabbedDocks, !AllowNestedDocks
    VerticalTabs = 0x10, // implies AllowTabbedDocks
    GroupedDragging = 0x20 // implies AllowTabbedDocks
    };
    Q_ENUM(DockOption)
    Q_DECLARE_FLAGS(DockOptions, DockOption)
    Q_FLAG(DockOptions)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    这几个宏也不是标准C++的内容,它们属于Qt的属性系统,是元对象系统的一部分。使用属性系统的类必须是QObject的子类,还得包含宏Q_OBJECT。

    在标准C++中,为了保证封装性,我们经常声明一个私有变量,然后声明两个公有函数,即set函数和get函数。在Qt中我们可以使用宏Q_PROPERTY来实现这些,还包括信号的发射,后者实际是在set函数中实现的。

    Q_PROPERTY(type name
    READ getFunction
    [WRITE setFunction]
    [RESET resetFunction]
    [NOTIFY notifySignal] )

    Q_PROPERTY(type name
    MEMBER memberName
    [READ getFunction]
    [WRITE setFunction]
    [RESET resetFunction]
    [NOTIFY notifySignal] )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    这是Q_PROPERTY的两种简单而常用的形式。

    type 是指属性的类型,可以是 C++ 标准类型、类名、结构体、枚举等
    name 属性的名字,仅仅是一个用于标识属性的名字,不是实际存在的成员变量
    READ 标出该属性的读函数 getFunction,Qt 属性的读函数通常省略 get 三个字母。
    WRITE 标出该属性的写函数 setFunction,中括号表示可选,写函数不是必须的。
    RESET 标出该属性的重置函数
    resetFunction,重置函数将属性设为某个默认值,中括号表示可选,重置函数不是必须的。
    NOTIFY 标出该属性变化时发出的通知信号 notifySignal,中括号表示可选,这个信号不是必须的。
    在明确标出属性使用的成员变量的情况下,属性的读写函数可以省略不写,Qt 的 moc 工具会自动为成员变量生成读写代码。比如:

    READ, WRITE以及RESET可以被继承,也可以是虚函数。property的类型可以是QVariant支持的任何类型,也可以是用户定义的类型,这就是Q_ENUM()的作用了。
    枚举类型必须用Q_ENUM()宏注册,这也是元对象系统的一部分,然后就可以使用QObject::setProperty(); 我们必须为READ和WRITE提供自己的声明。
    结合以上几条,我们这样写一个类:

    class MainWindow : public QMainWindow
    {
    Q_OBJECT
    Q_PROPERTY(int value MEMBER m_value NOTIFY valueChanged);
    Q_PROPERTY(Priority prioity MEMBER m_priority NOTIFY priChanged);
    public:
    MainWindow(QWidget* parent= nullptr);
    ~MainWindow();
    enum Priority{Low,High, VeryHigh};
    Q_ENUM(Priority);
    signals:
    void valueChanged();
    void priChanged();
    private:
    Ui::MainWindow* ui;
    int m_value;
    Priority m_priority;
    };
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    这样就可以在类外调用相关函数了:

    m.setProperty("value",15);
    m.setProperty("prioity",MainWindow::VeryHigh);

    qDebug()<<"value:"<<m.property("value").toInt();
    qDebug()<<"prioity value:"<<m.property("prioity").toInt();
    qDebug()<<m.dynamicPropertyNames();
    1
    2
    3
    4
    5
    6
    还有一个宏Q_FLAG(), 它与Q_ENUM()类似, 也是注册枚举类型, 但可以使用|操作。一个I/O类可能有枚举值Read和Write ,那么QObject::setProperty()就可以接受Read | Write。记得必须用Q_DECLARE_FLAGS完成注册

    还有一个宏Q_CLASSINFO(),在类的声明里添加类附加信息,比如:

    Q_CLASSINFO("Version", "1.0.0")
    1
    附加信息也是成对的“名称-值”,不过注意 名称和值 都是普通字符串。如果希望在运行时查询类的附加信息,可以先用 QObject::metaObject() 获取当前对象包含的元对象数据,然后使用 QMetaObject::​classInfo 函数查询某个序号的附加信息:

    //类内声明
    Q_CLASSINFO("Version", "1.0.0")
    Q_CLASSINFO("Author", "Winland")

    //类外使用
    //获取类的附加信息
    const QMetaObject *pMO = w.metaObject();

    //附加信息个数
    int nInfoCount = pMO->classInfoCount();

    //打印所有的附加信息
    for(int i=0; i<nInfoCount; i++)
    {
    QMetaClassInfo info = pMO->classInfo(i);
    qDebug()<<info.name()<<" "<<info.value();
    }
    ---------------------
    作者:SilentAssassin
    来源:CSDN
    原文:https://blog.csdn.net/yao5hed/article/details/81142358?utm_source=copy
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    CodeForces 522B 手速题
    mybatis多数据源报错
    as依赖解决报错
    As 400错
    maven直接饮用jar包的写法
    测试一下多线程同时往list中添加元素会不会出问题
    jmeter中判断数据库是否存在相应的记录
    jmeter打开图形化界面时指定代理
    wz
    初阳胜阴
  • 原文地址:https://www.cnblogs.com/findumars/p/9799974.html
Copyright © 2020-2023  润新知