Qt核心模块将这些特性添加到c++中:
The Meta-Object System
Qt的元对象系统为对象间通信、运行时类型信息和动态属性系统提供了信号和插槽机制。
元对象系统基于以下三点:
- QObject类为可以利用元对象系统的对象提供了一个基类。
- 类声明的私有部分中的Q_OBJECT宏用于启用元对象特性,例如动态属性、信号和槽。
- 元对象编译器(moc)为每个QObject子类提供实现元对象特性所需的代码。
QMetaObject *QObject::metaObject()
className():
QObject *obj = new QPushButton;
obj->metaObject()->className(); // returns "QPushButton"
QPushButton::staticMetaObject.className(); // returns "QPushButton"
inherits():
QTimer *timer = new QTimer; // QTimer inherits QObject
timer->inherits("QTimer"); // returns true
timer->inherits("QObject"); // returns true
timer->inherits("QAbstractButton"); // returns false
// QVBoxLayout inherits QObject and QLayoutItem
QVBoxLayout *layout = new QVBoxLayout;
layout->inherits("QObject"); // returns true
layout->inherits("QLayoutItem"); // returns true (even though QLayoutItem is not a QObject)
qobject_cast():
QObject *obj = new MyWidget;
QWidget *widget = qobject_cast<QWidget *>(obj);
MyWidget *myWidget = qobject_cast<MyWidget *>(obj);
QLabel *label = qobject_cast<QLabel *>(obj);
// label is 0
The Property System
要声明一个属性,在继承QObject的类中使用Q_PROPERTY()宏。
下面是取自类QWidget的属性声明的一些典型示例:
Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
下面是一个示例,展示了如何使用member关键字将成员变量导出为Qt属性。注意,必须指定NOTIFY信号才能允许QML属性绑定。
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;
accessor function:
READ 如果没有指定成员变量,则需要READ访问器函数。它用于读取属性值。理想情况下,为此目的使用const函数,它必须返回属性的类型或对该类型的const引用。
WRITE 访问器函数是可选的。用于设置属性值。它必须返回void,并且必须只有一个参数,要么是属性的类型,要么是指向该类型的指针或引用。例如,QWidget::enabled具有WRITE功能QWidget::setEnabled()。只读属性不需要WRITE函数。
MEMBER 给定的成员变量可读可写,而不需要创建READ和WRITE访问器函数。如果需要控制变量访问,除了成员变量关联之外,还可以使用READ或WRITE访问器函数(但不能两者都使用)。
RESET 是可选的,它用于将属性设置回其上下文特定的默认值。例如,QWidget::cursor具有典型的READ和WRITE函数,QWidget::cursor()和QWidget::setCursor(),并且它还有一个RESET函数,QWidget::unsetCursor(),因为没有调用QWidget::setCursor()可以意味着重置到特定于上下文的光标。RESET函数必须返回void且不带参数。
NOTIFY 信号方法是可选的. 它需要在该类中指定一个现有的信号,每当属性的值发生变化时,该信号就会发出。
QObject::property() and QObject::setProperty() QMetaProperties
QPushButton *button = new QPushButton;
QObject *object = button;
button->setDown(true);
object->setProperty("down", true);
button->setProperty("flat",true);
QVariant isflat = button->property("flat");
qDebug() << isflat << endl;//QVariant(bool, true)
QObject *object = ...
const QMetaObject *metaobject = object->metaObject();
int count = metaobject->propertyCount();
for (int i=0; i<count; ++i) {
QMetaProperty metaproperty = metaobject->property(i);
const char *name = metaproperty.name();
QVariant value = object->property(name);
...
}
A Simple Example:
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
public:
MyClass(QObject *parent = nullptr);
~MyClass();
enum Priority { High, Low, VeryHigh, VeryLow };
Q_ENUM(Priority)
void setPriority(Priority priority)
{
m_priority = priority;
emit priorityChanged(priority);
}
Priority priority() const
{ return m_priority; }
signals:
void priorityChanged(Priority);
private:
Priority m_priority;
};
有两种方法设置属性
MyClass *myinstance = new MyClass;
QObject *object = myinstance;
myinstance->setPriority(MyClass::VeryHigh);
object->setProperty("priority", "VeryHigh");
QObject::setProperty()也可用于在运行时为类的实例添加新属性。当使用名称和值调用它时,如果QObject中存在具有给定名称的属性,并且给定的值与属性的类型兼容,则该值将存储在属性中,并返回true。如果该值与属性的类型不兼容,则不会更改属性,并返回false。但是,如果具有给定名称的属性在QObject中不存在(即,如果它没有使用Q_PROPERTY()声明),则一个具有给定名称和值的新属性将自动添加到QObject中,但仍然返回false。这意味着不能使用返回false来确定是否实际设置了特定属性,除非您事先知道该属性已经存在于QObject中。
参考连接:
https://doc.qt.io/qt-6/qtcore-index.html