Qt正确使用属性语法
Qt proper usage of properties syntax
当我使用Q_PROPERTY
定义属性时,我确保继承QObject
并在类定义开始时声明Q_OBJECT
宏。我这样声明这个属性:
Q_PROPERTY(QString MyProp READ getMyProp WRITE setMyProp)
,然后我这样使用:
myObject->MyProp = QString("test");
它告诉我没有MyProp
这样的成员。有什么问题吗?
当然没有这样的成员,因为您自己已经说过getter称为getMyProp
, setter称为setMyProp
。成员MyProp
的定义完全取决于您。下面,我将展示如何定义这样的成员。
我们还应该注意到,在Qt中,习惯上不会在getter前面加上get
,而是简单地将其命名为属性之后。这样就有
Q_PROPERTY(int foo READ foo WRITE setFoo)
// rather than
Q_PROPERTY)int foo READ getFoo WRITE setFoo)
可能的解决方案包括:
(1)直接访问属性的数据成员——这会破坏属性系统授予的封装,因此不建议这样做。
class Direct : public QObject {
Q_OBJECT
Q_PROPERTY(int prop MEMBER prop)
public:
int prop;
};
Direct d;
d.prop = 3;
Q_ASSERT(d.property("prop").toInt() == 3);
最后一行之所以有效,是因为moc生成了简单的getter和setter代码,这些代码随后可以通过元对象系统访问。该代码嵌入在元数据实现中,不会导致任何方法被添加到类本身。
(2)有一个返回引用的getter。当getter和setter都不重要时,这是最简单、开销低的方法。
class GetSet : public QObject {
Q_OBJECT
Q_PROPERTY(int prop READ prop WRITE setProp)
int m_prop;
public:
int & prop() { return m_prop; }
int prop() const { return m_prop; }
void setProp(int prop) { m_prop = prop; }
};
GetSet gs;
gs.prop() = 3; // assignment syntax through "getter"
Q_ASSERT(gs.property("prop").toInt() == 3);
gs.setProp(4); // setter syntax
Q_ASSERT(gs.property("prop").toInt() == 4);
(3)向属性公开充当代理的成员。这允许在没有调用语法的情况下使用代理:obj.prop
而不是obj.prop()
。
(3a)我们可以使用Qt属性系统访问一个命名的属性。QMetaProperty
充当缓存,以避免在每次属性访问时重复查找名称。在每个属性访问上执行QVariant
转换。
template <typename B, typename T> class PProxy {
Q_DISABLE_COPY(PProxy)
B * obj;
QMetaProperty prop;
public:
PProxy(B & o, const char * p) : obj(&o),
prop(o.metaObject()->property(o.metaObject()->indexOfProperty(p))) {}
T operator=(const T & val) { prop.write(obj, val); return val; }
T operator=(T && val) { prop.write(obj, val); return val; }
operator T() const { return prop.read(obj).value<T>(); }
};
class ViaPProxy : public QObject {
Q_OBJECT
Q_PROPERTY(int prop READ getProp WRITE setProp)
int m_prop;
public:
PProxy<Direct, int> prop;
ViaPProxy() : prop(*this, "prop") {}
int getProp() const { return m_prop; }
void setProp(int val) { m_prop = val; }
}
ViaPProxy vpp;
vpp.prop = 3; // invokes the setter through a proxy
Q_ASSERT(vpp.prop == 3);
(3b)代理可以直接使用getter和setter,而不是通过Qt属性系统和QVariant
转换。这比(3a)的开销低,但要求存在getter和可选的setter。
template <typename B, typename T,
T (B::*get)() const, void (B::*set)(T) = 0> class DProxy {
Q_DISABLE_COPY(DProxy)
B & obj;
public:
DProxy(B & o) : obj(o) {}
T operator=(const T & val) { (obj.*set)(val); return val; }
T operator=(T && val) { (obj.*set)(std::forward<T>(val)); return val; }
operator T() const { return (obj.*get)(); }
};
class ViaDProxy : public QObject {
Q_OBJECT
Q_PROPERTY(int prop READ getProp WRITE setProp)
int m_prop;
public:
DProxy<Direct, int, &ViaDProxy::get, &ViaDProxy::set> prop;
ViaDProxy() : prop(*this) {}
int getProp() const { return m_prop; }
void setProp(int val) { m_prop = val; }
}
ViaDProxy vdp;
vdp.prop = 3; // invokes the setter through a proxy
Q_ASSERT(vdp.prop == 3);
相关文章:
- Qt Quick-如何仅从c++代码与qml属性交互
- QT 样式表主题,适用于使用属性选择器的整个应用程序
- 如何在Qt C++中向自定义控件添加属性?
- 我想获取点的属性,它报告错误 C3867:"point::output_x":非标准语法;使用"&"创建指向成员的指针
- 如何删除Qt设计器中自定义插件的QString属性的"translatable"复选框?
- 将 Qt 属性枚举值打印为键字符串
- Qt的新信号/时隙语法问题 - 连接到一个简单的函数
- QT和新的信号槽语法,QApplication::退出主功能外的插槽
- 使用具有新信号槽语法的Qt插件系统在接口类中声明信号
- 应用于类型别名声明的 [[maybe_unused]] 属性的语法
- 当删除上下文属性中的QLIST对象时,QT QML应用程序崩溃
- 如何在Qt中解析未知的xml并获取其中的所有属性
- 属性语法中的 C++ alignas 说明符
- boost :: Spirit :: Karma语法:逗号从结构上划定了带有选件属性的输出
- 在Qt信号和插槽中使用lambda语法并访问传递的参数
- 将gcc属性与C++11属性语法结合使用
- OpenCL C++上下文属性语法
- 将项目属性与qt中的事件一起传递到主窗口
- 如何获得xml属性与此语法使用Qt DOM
- Qt正确使用属性语法