Qt之Q_PROPERTY使用实例

标题一、Q_PROPERTY的简介

Q_PROPERTY与信号槽(signals/slots)同属Qt Meta Object System-元对象系统,前者提供了动态属性封装,后者提供了方便的对象间通信功能。所以想要实现Q_PROPERTY功能也要继承QObject类并添加Q_OBJECT关键字。

二、Q_PROPERTY的用处

Qt之Q_PROPERTY使用实例_第1张图片

Q_PROPERTY的第一个显而易见的用处是它在代码文件与UI文件之间建立了联系,查看Qt源文件也可以看到,QWidget中定义的大部分属性,也可以在UI文件中找的到,且基本都是可以设置的。

不过在实际工作中,对于自定义的属性还需要手动在UI文件中键入关键字,无法自动生成,存在一定错误的风险。

Q_PROPERTY的第二个作用是提供给脚本(比如QtScript,QML)和元对象系统(比如QObject::property/setProperty)使用。[①]

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

常用关键字解释如下:[②]

  • READ、WRITE、MEMBER 三个关键字指定了属性的读写性。Q_PROPERTY声明必须有一个READ或MEMBER关键字,否则moc时将会告警。

  • READ关键字用来读取属性值。因此用const限定。它的返回值类型必须为属性类型或者属性类型的引用或者指针,不能是其他类型,例如:QWidget::hasFocus()。

  • WRITE关键字可选,它用来设置属性值,它的返回值必须为void型,而且必须要含有一个参数,例如:QWidget::setEnabled()。

  • MEMBER 用于将类中已有的成员变量设置为属性值,在你偷懒不想编写读写函数时可以使用。

  • RESET函数能够把property设置成其默认状态,它也是可选的。复位功能必须返回void,并且不带参数。

  • 一个NOTIFY信号是可选的,如果定义,它要求提供一个信号。这个信号在值发生改变时会自动被触发,如QWidget::windowTitleChanged。

  • 如果定义了"STORED"属性表明这是一直存在的,如QWidget::minimumSize。

  • "DESIGNABLE"属性表明该property能在GUI builder(一般为Qt Designer)可见,不带该参数时默认可见,如QWidget::visible。

  • USER 属性,表明是否可以被用户所编辑,如QLineEdit::text

  • CONSTANT 设定属性是不可修改的 所以不能跟WRITE或者NOTIFY同时出现

  • FINAL 表明该属性不会被派生类中重写。

四、Q_PROPERTY的使用实例

项目中经常会遇到一类样式如下,要求程序对密码输入框进行检查,如果输入不合法则输入框的边框会变红。也就是说输入框实际存在两种状态——正常和错误,那我们用property搭配qss的属性选择器来实现此功能。
Qt之Q_PROPERTY使用实例_第2张图片

我们新建一个CheckLineEdit类,继承于QLineEdit,并添加status属性

#pragma once

#include 
#include "QLineEdit"

class CheckLineEdit : public QLineEdit
{
    Q_OBJECT
    Q_PROPERTY(QString status MEMBER checkStatus WRITE setCheckStatus READ getCheckStatus)

public:
    CheckLineEdit(QWidget *parent);
    ~CheckLineEdit();
    void setCheckStatus(const QString&checkStatus);
    QString getCheckStatus() const { return this->checkStatus; }

private:
    QString checkStatus;

private slots:
    void slotSanityCheck();
};

在cpp文件中,我们以6个字符为阈值,设定自定义的检查规则如下:

#include "CheckLineEdit.h"
#include 

CheckLineEdit::CheckLineEdit(QWidget *parent)
    : QLineEdit(parent)
{
    connect(this, SIGNAL(textChanged(QString)), this, SLOT(slotSanityCheck()));
}

CheckLineEdit::~CheckLineEdit()
{
}

void CheckLineEdit::setCheckStatus(const QString&checkStatus)
{
    this->checkStatus = checkStatus;
}

void CheckLineEdit::slotSanityCheck()
{
    if (this->text().length() < 6)
    {
        this->setProperty("status", "Normal");
    }
    else
    {
        this->setProperty("status", "Warning");
    }
    this->style()->polish(this);
}

之后在其他QWidget中放置并提升一个CheckLineEdit,并设置自定义的qss样式如下:

QLineEdit[status = "Normal"]
{
    border: 1px solid #CCCCCC;
}
QLineEdit[status = "Warning"]
{
    border: 1px solid #FF3E33;
}

运行查看效果如下:
在这里插入图片描述

可以看到,输入框的颜色跟随输入文本的长度变化,我们实现了需要的功能。

之后,我们做一个小尝试,尝试在UI文件中设置自定义属性并让其实时生效

打开已经提升过的QWidget文件,在属性编辑器中加入我们之前设置好的属性“status”,之后修改它的值为“Warning”看看会发生什么。

可以看到,这里设置了动态属性后,UI实时预览了我们自定义的属性样式,根源是我们在UI样式中使用了对应的属性选择器,又新增了动态属性status。

此时我们再次运行程序后,setCheckStatus函数将会被调用,且输入框直接显示Warning时的样式,这样再次印证了我们前文所述的“代码与UI文件的联系”。

最后碍于篇幅,这里将C++与QML脚本语言交互的内容[⑤]按下不表,有兴趣的读者可以自行查看参考资料五,此二者交互中也体现出了Q_PROPERTY的妙用。

五、参考资料

① QT之Qt之Q_PROPERTY宏理解 - 我来乔23 - 博客园 (cnblogs.com)

② 传说中的Q_PROPERTY怎么使用_qq303103757的博客-CSDN博客_q_property

③【Qt】Q_PROPERTY():属性系统_郭老二的博客-CSDN博客_q_property

④Qt 中的属性系统(Property System) - 知乎 (zhihu.com)

⑤QT之Qt之Q_PROPERTY宏理解 - 我来乔23 - 博客园 (cnblogs.com)

你可能感兴趣的:(qt5,qt,ue4,ui)