Qt核心特点

参考书籍:

  • 王维波, 栗宝鹃, & 侯春望. (2018). Qt5.9 C++开发指南 (1st ed.). 人民邮电出版社.

元对象系统

Qt元对象系统的三个基础:

  • QObject是所有使用元对象系统的类的基类。
  • 在一个类的private部分声明Q_OBJECT宏,使得类可以使用元对象的特性,如动态属性、信号和槽。
  • MOC(元对象编译器)为每个QObject的子类提供必要的代码来实现元对象系统的特性。

除了信号与槽,元对象还提供以下一些功能:

  • QObject::metaObject()函数返回类关联的元对象,元对象QMetaObject包含了访问元对象的一些接口函数,例如QMetaObject::className()函数可在运行时返回类的名称字符串。
    QObject *obj = new QPushButton;
    obj->metaObject()->className();//返回"QPushButton"
    
  • QMetaObject::newInstance()函数创建类的一个新的实例。
  • QObject::inherits(const char *className)函数判断一个对象实例是否是名称为className的类或QObject的子类的实例。例如:
    QTimer *timer = new QTimer;    //QTimer 是QObject的子类
    timer->inherits("QTimer");    //返回true
    timer->inherits("QObject");    //返回true
    timer->inherits("QAbstractButton");    //返回false,不是QAbstractButton的子类
    
  • QObject::tr()QObject::trUTF8()函数可翻译字符串,用于多语言界面设计。
  • QObject::setProperty()QObject::property函数可用于通过属性名动态设置和获取属性值。

对于QObject及其子类,可以用qobject_cast来投射,qobject_cast并不区分Qt内建的类型和用户自定义类型。

属性系统

1.属性定义

Q_PROPERTY宏可用于定义属性,它是基于元对象系统实现的。Qt的属性系统与C++编译器无关,可以用任何标准的C++编译器编译定义了属性的Qt C++程序、

使用格式如下:

Q_PROPERTY(type name
                READ getFunction [WRITE setFunction]
                [RESER resetFunction]
                [NOTIFY notifySignal]
                [REVISION int]
                [DESIGNABLE bool]
                [SCRIPTABLE bool]
                [STORED bool]
                [USER bool]
                [CONSTANT]
                [FINAL] )

该宏定义一个返回值类型为type,名称为name的属性,用READWRITE关键字定义属性的读取、写入函数,还有其他的一些关键字定义属性的一些操作特性。属性的类型可以是QVariant支持的任何类型,也可以用于自定义类型。

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

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

例子:

Q_PROPERTY(bool focus    READ hasFocus)
Q_PROPERTY(bool enabled    READ isEnabled    WRITE setEnabled)
Q_PROPERTY(QCursor cursor    Read cursor    WRITE setCursoe    RESET unsetCursor)
2.属性的使用

不管是否用READ和WRITE定义了接口函数,只要知道属性名称,就可以通过QQObject::property()读取属性值,并通过QQObject::setProperty()设置属性值。例如:

QPushButton *button = new QPushButton;
QObject *object = button;
object->setProperty("flat", true);
bool   isFlat = object->property("flat");
3.动态属性

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

例如,在数据表编辑界面上,一些字段是必填字段,就可以在初始化界面时为这些字段的关联显示组件定义一个新的required属性,并设置为"true",如:

editName->setProperty("required", "true");
dombSex->setProperty("required", "true");
checkAgree->setProperty("required", "true");

然后,可以应用下面的样式定义将这种必填字段的背景颜色设置为亮绿色。

*[required="true"] (background-color: lime);
4.类的附加信息

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

class QMyClass : public QObject
{
        Q_OBJECT
        Q_CLASSINFO("author", "Wang")
        Q_CLASSINFO("company", "UPC")
        Q_CLASSINFO("version", "3.0.1")
public:
    ...
}

Q_CLASSINFO()宏定义附加类信息后,可以通过元对象的一些函数获取类的附加信息,如classInfo(int)获取某个附加信息,函数原型定义如下:

QMetaClassInfo QMetaObject::classInfo(int index) const

返回值是QMetaClassInfo类型,由name()value()两个函数,可以获得类附加信息的名称和值。

信号与槽

1.connect()的不同参数形式

connect有多种形式:

 QMetaObjcect::Connection QObject::connect(const QObject* sender,
                                              const char *signal, 
                                              const QObject *receiver,
                                              const char *method,
                                              Qt::ConnectionType type = Qt::AutoConnection
                                              );
                                              
QMetaObject::Connection QObject::connect(const QObject *sender,
                                             const QMetaMethod &signal,
                                             const QObject *receiver,
                                             const QMetaMethod &method,
                                             Qt::ConnectionType type = Qt::AuotConnection
                                             );

第一种是通用的,调用格式:

connnect(sender, SLOT(signal()), receiver, SLOT(slot()));

例如:

connect(sender, SLOT(valueChanged(int)), this, SLOT(updateStatus(int)));

第二种仅限于信号名称唯一的(即,没有参数不同而同名的两个信号),调用例子:

connect(sender, &QLineEdit::textChanged, this, &widget::on_textChanged)l

第二种在对参数比较多的信号时比较方便。

参数 Qt::ConnectionType type表示信号与槽的关联方式。

  • QAutoConnection(缺省值)
    • 如果信号的接收者与发射者在同一个线程,就使用Qt::DirectConnection方式;否则使用Qt::QueuedConnection方式,在信号发生时自动确定关联方式。
  • Qt::DirectConnection
    • 信号发射时槽函数立即执行,槽函数与信号在同一个线程。
  • Qt::QueuedConnection
    • 在事件循环回到接收者线程后执行槽函数,槽函数与信号在不同的线程。
2.使用sender()获得信号发射者

在槽函数里,使用QObject::sender()可以获取信号发射者的指针。如果知道信号发射者的类型,可用将指针投射为确定的类型,然后使用这个确定类的接口函数。

例如,在QSpinBoxvalueChanged(ind)信号的槽函数里,可以通过sender()qobject_cast获得信号发射者的指针,从而对信号发射者进行操作。

QSpinBox *spinBox = qobject_cast<QSpinBox *>(sender());
3.自定义信号及其使用

在自己设计的类里也可以自定义信号,信号就是在类定义里声明的一个函数,但是这个函数无需实现,只需发射(emit)。

例如,在下面的自定义类QPersonsignals部分定义一个信号ageChanged(int)

class QPerson : public QObject{
    QOBJECT
private:
    int  m_age = 10;
public:
    void  incAge();
signals:
    void  ageChanged(int value);
}

信号函数必须是无返回值的函数,但是可以由入参,信号函数无需实现,只需在某些条件下发射信号。
例如,在incAge() 函数中发射信号,其代码如下:

void QPerson::incAge()
{
    m_age++;
    emit ageChanged(m_age);    //发射信号
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

barbyQAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值