对象属性事件

元对象系统

元对象系统提供了信号与槽机制

1.QObject类,为objects提供了一个可以利用元对象系统的基类。
2.Q_OBJECT宏: 在类的私有部分声明这个宏可以启用元对象特性,例如:动态属性、信号与槽。
3.Meta-Object编译器(moc): 为每个QObject子类生成必要的代码来实现元对象特性。
moc工具会读取C++源文件,如果发现有包含Q_OBJECT宏的类声明,就生成另外一个包含这些类的元对象代码的C++源文件。生成的源文件要么在类源文件里用#include包含,或者(更常见)与类的实现代码直接进行编译连接。

QObject::metaObject()返回类关联的meta-object对象。

QMetaObject::className()在运行时以字符串的形式返回类名,无需C++编译器提供运行时类别信息(RTTI)的支持。

QObject::inherits()返回一个对象是否是QObject继承树上一个类的实例。

QObject::tr()和QObject::trUtf8()提供国际化支持,将字符串翻译成指定的语言。

QObject::setProperty()和QObject::property()通过名称动态设置和获取属性。

QMetaObject::newInstance()构造类的一个新实例。
qobject_cast()动态转换QObject类的类型。qobject_cast()函数和标准C++的dynamic_cast()功能类似

    QObject *obj=new mywidget;
    QWidget  *wid=qobject_cast<QWidget *>(obj);
    wid->setObjectName("widget");
    mywidget *myw=qobject_cast<mywidget *>(wid);
属性

1.要声明一个属性,在继承QObject的类中使用Q_PROPERTY()宏


2.一个属性的行为就像一个类的数据成员,但它有通过元对象系统访问的附加功能。

声明属性需求
  • 如果MEMBER关键字没有被指定,则一个READ访问函数是必须的。它被用来读取属性值。理想的情况下,一个const函数用于此目的,并且它必须返回的是属性类型或const引用。比如:QWidget::focus是一个只读属性,通过READ函数QWidget::hasFocus()访问。

  • 一个WRITE访问函数是可选的,用于设置属性的值。它必须返回void并且只能接受一个参数,属性的类型是类型指针或引用,例如:QWidget::enabled具有WRITE函数QWidget::setEnabled()。只读属性不需要WRITE函数,例如:QWidget::focus没有WRITE函数。

  • 如果READ访问函数没有被指定,则MEMBER变量关联是必须的。这使得给定的成员变量可读和可写,而不需要创建READ和WRITE访问函数。如果需要控制变量访问,仍然可以使用READ和WRITE函数而不仅仅是MEMBER(但别同时使用)。

  • 一个RESET函数是可选的,用于将属性设置为上下文指定的默认值。例如:QWidget::cursor有READ和WRITE函数QWidget::cursor()和QWidget::setCursor(),同时也有一个RESET函数QWidget::unsetCursor(),因为没有可用的QWidget::setCursor()调用可以确定的将cursor属性重置为上下文默认的值。RESET函数必须返回void类型,并且不带任何参数。

  • 一个NOTIFY信号是可选的。如果定义了NOTIFY,则需要在类中指定一个已存在的信号,该信号在属性值发生改变时发射。与MEMBER变量相关的NOTIFY信号必须有零个或一个参数,而且必须与属性的类型相同。参数保存的是属性的新值。NOTIFY信号应该仅当属性值真正的发生变化时发射,以避免被QML重新评估。例如:当需要一个没有显式setter的MEMBER属性时,Qt会自动发射信号。

  • 一个REVISION数字是可选的。如果包含了该关键字,它定义了属性并且通知信号被特定版本的API使用(通常是QML);如果没有包含,它默认为0。

  • DESIGNABLE属性指定了该属性在GUI设计器(例如:Qt Designer)里的编辑器中是否可见。大多数的属性是DESIGNABLE (默认为true)。除了true或false,你还可以指定boolean成员函数。

  • SCRIPTABLE属性表明这个属性是否可以被一个脚本引擎操作(默认是true)。除了true或false,你还可以指定boolean成员函数。

  • STORED属性表明了该属性是否是独立存在的还是依赖于其它属性。它也表明在保存对象状态时,是否必须保存此属性的值。大多数属性是STORED(默认为true)。但是例如:QWidget::minmunWidth()的STROED为false,因为它的值从QWidget::minimumSize()(类型为QSize)中的width部分取得。

  • USER属性指定了属性是否被设计为用户可见和可编辑的。通常情况下,每一个类只有一个USER属性(默认为false)。例如: QAbstractButton::checked是(checkable)buttons的用户可修改属性。注意:QItemDelegate获取和设置widget的USER属性。

  • CONSTANT属性的出现表明属性是一个常量值。对于给定的object实例,常量属性的READ函数在每次被调用时必须返回相同的值。对于不同的object实例该常量值可能会不同。一个常量属性不能具有WRITE函数或NOYIFY信号。

  • FINAL属性的出现表明属性不能被派生类所重写。有些情况下,这可以用于效率优化,但不能被moc强制执行。必须注意不能覆盖一个FINAL属性。

  • 属性类型可以是QVariant支持的任何类型,或者是用户定义的类型。在这个例子中,类QDate被看作是一个用户定义的类型。

Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
   Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
    Q_PROPERTY(qreal spacing MEMBER m_spacing NOTIFY spacingChanged)
    Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged)
    ...
signals:
    void colorChanged();
    void spacingChanged();
    void textChanged(const QString &newText);

private:
    QColor  m_color;
    qreal   m_spacing;
    QString m_text;

一个属性可以使用常规函数QObject::property()和QObject::setProperty()进行读写,除了属性的名字,不用知道属性所在类的任何细节。

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

button->setDown(true);
object->setProperty("down", true);
事件

在Qt中,事件就是对象,派生自QEvent抽象类

事件的运行过程

当一个事件发生时Qt会构造一个事件的对象,它识别事件类型,将事件发送给特定的对象,而后特定的对象将会返回特定的bool


事件机制
bool QCoreApplication::notify(QObject * receiver, QEvent * event) [virtual]
发送事件给接收者,接收者处理并返回状态.


事件处理陈程序
相当于一个虚函数,你也可以自己重写虚函数


事件过滤器
所谓事件过滤就是提前截获发往某个对象的所有消息,根据需要屏蔽掉某一些,或者对某些消息提前进行些处理,其他的事件处理将不会接收到该事件.

//eventfilter.cpp
#include "eventfilter.h"
#include <QEvent>
#include <QKeyEvent>

bool eventfilter::eventFilter(QObject *to, QEvent *event)//event filter(write number only)
{
    static QString digits = QString("1234567890");
    if(event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*> (event);
        if( digits.indexOf(keyEvent->text()) != -1 )
        {
            return false;
        }
        return true;
    }
    return QObject::eventFilter(to, event);
}


//main.cpp
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    mywidget *myw=new mywidget;         //display widget
    eventfilter *eve=new eventfilter;   //evevt filter,it let textbroser write number only
    QTextEdit *textbrowser=new QTextEdit;
    textbrowser->installEventFilter(eve);//use filetr
    QVBoxLayout *layout=new QVBoxLayout(myw);
    layout->addWidget(textbrowser);
    myw->show();
    return a.exec();
}

发送事件
使用notify()函数直接给receiver发送事件。
postEvent(QObject* receiver, QEvent* event)
向事件队列中添加receiver和event。
简单说,sendEvent使用的是同步处理事件,postEvent使用的异步处理事件

QCoreApplication::sendEvent()
QCoreApplication::postEvent()

这里可以看到事件是如何处理的:
先送入Application的事件过滤器,看看是否在事件过滤器中处理
再查看receiver是否有此事件的过滤器
最后,将事件送入receiver的event接口。

常见的事件类型

QResizeEvent、QPaintEvent、QMouseEvent、QKeyEvent、QCloseEvent。

猜你喜欢

转载自blog.csdn.net/qq_33564134/article/details/81383178