Qt 属性系统

       属性系统 Qt Creator 帮助文档为《The Property System》

      属性系统是基于元对象系统实现的,Qt 的属性系统与C++编译器无关,任何标准的C++编译器都可以编译定义了Qt属性的C++程序。我的理解:C++ 类提供属性(成员变量)和方法,方法操作内部属性,Qt基于元对象定义一种操作类内部属性和方法的方式,即按照Qt属性系统定义属性,方法,就可以按照Qt的方式操作对应的内部属性和方法。

     Qt 提供一个 Q_PROPERTY() 宏可以定义属性,在QObject的子类中用宏Q_PROPERTY() 可以定义属性,具体格式如下:

  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])

     具体含义: Qt 使用Q_PROPERTY 宏定义一个返回值类型为 type,名称为 name 的属性,用 READ、WRITE 关键字定义属性的读取、写入函数,还有其他的一些关键字定义属性的一些操作特性。属性的类型可以是 QVariant 支持的任何类型,也可以用户自定义类型。

    Q_PROPERTY 宏定义属性的一些主要关键字的意义如下:

    1)READ 指定一个读取属性值的函数,没有 MEMBER 关键字时必须设置 READ。
    2)WRITE 指定一个设定属性值的函数,只读属性没有 WRITE 设置。
    3)MEMBER 指定一个成员变量与属性关联,成为可读可写的属性,无需再设置 READ 和 WRITE。
    4)RESET 是可选的,用于指定一个设置属性缺省值的函数。
    5)NOTIFY 是可选的,用于设置一个信号,当属性值变化时发射此信号。
    6)DESIGNABLE 表示属性是否在 Qt Designer 里可见,缺省为 true。
    7)CONSTANT 表示属性值是一个常数,对于一个对象实例,READ 指定的函数返回值是常数,但是每个实例的返回值可以不一样。具有 CONSTANT 关键字的属性不能有 WRITE 和 NOTIFY 关键字。
   8)FINAL 表示所定义的属性不能被子类重载。

    例如下面QWeidgt 的属性定义:

  Q_PROPERTY(bool focus READ hasFocus)
  Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
  Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)

        通过QObject::property() 和 QObject::setProperty() 就可以操作对应的属性,无论是否使用READ 或者WRITE 定义方法接口,只要知道属性名称都可以操作,例如:

 QPushButton *button = new QPushButton;
 QObject *object = button;

 button->setDown(true);
 object->setProperty("down", true); //等同setDown 为true
 bool down = object->Property("down");

      同时QObject::setProperty() 函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的,动态属性可以使用 QObject::property() 查询,就如在类定义里用 Q_PROPERTY 宏定义的属性一样。

    属性系统还有一个宏Q_CLASSINFO() 可以为类的元对象定义 名称 和 值的信息,如:

Q_CLASSINFO("Version", "3.0.0")  //定义
QMetaClassInfo QMetaObject::classInfo(int index) const   //调用该函数就可以获取类的附加信息
const char *QMetaClassInfo::name() const     //获取附加信息的名称     
const char *QMetaClassInfo::value() const   //获取附加信息的值

来一个完整的实例,该实例来自《Qt 5.9 c++ 开发指南》这本书:

//qperson.h 
#ifndef QPERSON_H
#define QPERSON_H

#include <QObject>

class QPerson : public QObject
{
    Q_OBJECT

    Q_CLASSINFO("author","Wang")
    Q_CLASSINFO("company","UPC")
    Q_CLASSINFO("version","1.0.0")

    Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged)
    Q_PROPERTY(QString name MEMBER m_name)
    Q_PROPERTY(int score MEMBER m_score)
private:
    int  m_age=10;
    QString m_name;
    int     m_score=79;
public:
    explicit QPerson(QString fName, QObject *parent = nullptr);

    int     age();
    void    setAge(int value);

    void    incAge();
signals:
    void    ageChanged( int  value);

public slots:
};

#endif // QPERSON_H

//qperson.cpp
#include "qperson.h"

QPerson::QPerson(QString fName,QObject *parent) : QObject(parent)
{ //构造函数
    m_name=fName;
}

int QPerson::age()
{ //返回age
    return  m_age;
}

void QPerson::setAge(int value)
{//设置age
    m_age=value;
    emit ageChanged(m_age); //发射信号
}

void QPerson::incAge()
{
    m_age++;
    emit ageChanged(m_age);//发射信号
}
//qmywidget.h

#ifndef QMYWIDGET_H
#define QMYWIDGET_H

#include <QWidget>
#include "qperson.h"

namespace Ui {
class QmyWidget;
}

class QmyWidget : public QWidget
{
    Q_OBJECT

private:
    QPerson *boy;
    QPerson *girl;

public:
    explicit QmyWidget(QWidget *parent = 0);
    ~QmyWidget();

private:
    Ui::QmyWidget *ui;

signals:

private slots:
//自定义槽函数
    void   on_ageChanged(int  value);
    void   on_spin_valueChanged(int arg1);

//界面按钮的槽函数
    void on_btnClear_clicked();
    void on_btnBoyInc_clicked();
    void on_btnGirlInc_clicked();
    void on_btnClassInfo_clicked();
};

#endif // QMYWIDGET_H

//qmywidget.cpp
#include "qmywidget.h"
#include "ui_qmywidget.h"
#include  <QMetaProperty>

QmyWidget::QmyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::QmyWidget)
{//构造函数
    ui->setupUi(this);

    boy=new QPerson("王小明");
    boy->setProperty("score",95);
    boy->setProperty("age",10);
    boy->setProperty("sex","Boy");//动态属性
//    connect(boy,SIGNAL(ageChanged(int)),this,SLOT(on_ageChanged(int)));
    connect(boy,&QPerson::ageChanged,this,&QmyWidget::on_ageChanged);

    girl=new QPerson("张小丽");
    girl->setProperty("score",81);
    girl->setProperty("age",20);
    girl->setProperty("sex","Girl");//动态属性
    connect(girl,&QPerson::ageChanged,this,&QmyWidget::on_ageChanged);

    ui->spinBoy->setProperty("isBoy",true); //动态属性
    ui->spinGirl->setProperty("isBoy",false);

//  不能使用此形式,因为QSpinBox有两种参数形式的valueChanged()信号
//    connect(ui->spinGirl,&QSpinBox::valueChanged,
//            this,&QmyWidget::on_spinBoy_valueChanged);
    connect(ui->spinGirl,SIGNAL(valueChanged(int)),
            this,SLOT(on_spin_valueChanged(int)));
    connect(ui->spinBoy,SIGNAL(valueChanged(int)),
            this,SLOT(on_spin_valueChanged(int)));
}

QmyWidget::~QmyWidget()
{
    delete ui;
}

void QmyWidget::on_ageChanged( int value)
{//响应QPerson的ageChanged()信号
    Q_UNUSED(value);
    QPerson *aPerson = qobject_cast<QPerson *>(sender()); //类型投射
    QString hisName=aPerson->property("name").toString(); //姓名
//    QString hisName=aPerson->name(); //获取姓名,错误
    QString hisSex=aPerson->property("sex").toString(); //动态属性
    int hisAge=aPerson->age();//通过接口函数获取年龄
//    int hisAge=aPerson->property("age").toInt();//通过属性获得年龄

    ui->textEdit->appendPlainText(hisName+","+hisSex
                               +QString::asprintf(",年龄=%d",hisAge));
}

void QmyWidget::on_btnClear_clicked()
{//"清空文本框"按钮
    ui->textEdit->clear();
}

void QmyWidget::on_btnBoyInc_clicked()
{//"boy长大一岁"按钮
    boy->incAge();
}

void QmyWidget::on_btnGirlInc_clicked()
{//"girl长大一岁"按钮
    girl->incAge();
}

void QmyWidget::on_spin_valueChanged(int arg1)
{//响应界面上spinBox的valueChanged(int)信号
    Q_UNUSED(arg1);
    QSpinBox *spinBox = qobject_cast<QSpinBox *>(sender());
    if (spinBox->property("isBoy").toBool())
        boy->setAge(spinBox->value());
    else
        girl->setAge(spinBox->value());
}

void QmyWidget::on_btnClassInfo_clicked()
{//"类的元对象信息"按钮
//    const QMetaObject *meta=boy->metaObject();
    const QMetaObject *meta=girl->metaObject();
//    const QMetaObject *meta=ui->spinBoy->metaObject();
    ui->textEdit->clear();

    ui->textEdit->appendPlainText("==元对象信息==\n");
    ui->textEdit->appendPlainText(QString("类名称:%1\n").arg(meta->className()));

    ui->textEdit->appendPlainText("property");
    for (int i=meta->propertyOffset();i<meta->propertyCount();i++)
    {
        const char* propName=meta->property(i).name();
        ui->textEdit->appendPlainText(
           QString("属性名称=%1,属性值=%2").arg(propName).arg(boy->property(propName).toString()));
    }

    ui->textEdit->appendPlainText("");
    ui->textEdit->appendPlainText("classInfo");
    for (int i=meta->classInfoOffset();i<meta->classInfoCount();++i)
    {
       QMetaClassInfo classInfo=meta->classInfo(i);
        ui->textEdit->appendPlainText(
           QString("Name=%1; Value=%2").arg(classInfo.name()).arg(classInfo.value()));
    }

}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值