前言
很多时候需要界面存储一些数据或信息,这样可以根据这些数据或信息来了解或获取点什么。可以说给界面增加一个标记,让我们更容易辨识。
我之前一直习惯给列表项QListWidgetItem或者树项QTreeWidgetItem携带一些数据,比如id,用setData来实现。所以这次就想QWidget有没有类似的方法,结果就找到了setUserData。后来在mac os中重新编译时,发现setUserData不可用了,建议用setProperty替换。
用法
我现在用的Qt的版本是Qt5.9 windows,方法setUserData已经在官方的帮助文档中看不到了,只能在.h中看到他的声明;而setProperty则可以在帮助文档中看到。
下面是qobject.h文件中的声明,QT_NO_PROPERTIES和QT_NO_USERDATA应该是为了版本的兼容。
#ifndef QT_NO_PROPERTIES
bool setProperty(const char *name, const QVariant &value);
QVariant property(const char *name) const;
QList<QByteArray> dynamicPropertyNames() const;
#endif // QT_NO_PROPERTIES
#ifndef QT_NO_USERDATA
static uint registerUserData();
void setUserData(uint id, QObjectUserData* data);
QObjectUserData* userData(uint id) const;
#endif // QT_NO_USERDATA
setUserData的用法
通过声明我们可以看到:要想设置用户的数据,数据则必须继承QObjectUserData,我用了结构体来存储数据
struct LevelValue:QObjectUserData {
int iLevel;
int iFormType; //界面类型
};
然后新建此数据对象,然后将此对象的指针交由此保存。
//设置界面等级
LevelValue* data=new LevelValue;
data->iLevel=2;
data->iFormType=0;
this->setUserData(Qt::UserRole,data);
然后同userData来获取数据,根据数据进行相应的处理。
QWidget* pCurWidget=ui->formStacked->widget(index);
LevelValue *data=(LevelValue*)pCurWidget->userData(Qt::UserRole);
if(data!=NULL)
{
int iType=data->iFormType;
m_latestForms[iType]=pCurWidget;
}
setProperty的用法
通过上面的介绍多少觉得setUserData的方法有些别扭,特别是数据必须要继承QObjectUserData,挺不方便的,而且仅此用得到这个类吧,感觉也不通用,所以他被换掉也是有原因的。
而setProperty则方便很多:它的数据是QVariant 类型的,这个类型就像var一样的好用(这个类型我在以前的博客有介绍,点这里)。若自定义的类型记得用宏Q_DECLARE_METATYPE注册到元对象系统,枚举用Q_ENUMS注册。
通过名字,可以了解到这是设置属性,Qt中有庞大的属性系统,这个方法是动态添加属性。若想详细的了解Qt属性系统,可以通过亮大的博客了解。注意的是:如果QObject中一个指定名称的属性已经存在,并且如果给定的值与属性的类型兼容,那么,值就被存储到属性中,然后返回true。如果值与属性类型不兼容,属性的值就不会发生改变,会返回false。但是如果QObject中一个指定名称的属性不存在(例如:未用Q_PROPERTY()声明),一个带有指定名称和值的新属性就被自动添加到QObject中,但是依然会返回false。这意味着返回值不能用于确定一个属性是否被设置值,除非事先知道这个属性已经存在于QObject中。
//.h声明
struct LevelValue {
int iLevel;
int iFormType;
};
Q_DECLARE_METATYPE(LevelValue)
LevelValue data;
data.iLevel=2;
data.iFormType=0;
QVariant var=QVariant::fromValue(data);
this->setProperty("LevelValue",var);
QVariant var=pCurWidget->property("LevelValue");
//可加判断
if(var.canConvert<LevelValue>())
{
LevelValue data=var.value<LevelValue>();
}
结束语
以后还是用setProperty吧!