QVariant 非常重要,可以存储很多种不同的类型,例如 int, QString, QRect, QPoint 等,其构造函数有很多个,参数是很多种不同的常用类型,还内置了可以直接转换 QVaraint 到某些类型的函数,如 toInt(), toString(), toPoint(), toSize() 等,还是 QObject 动态 property 机制的关键,除了支持内置的类型外,QVariant 还被设计成可以存储我们自己定义的类型。
关键术语:
Q_DECLARE_METATYPE
qRegisterMetaType
qRegisterMetaTypeStreamOperators
operator QVariant()
自定义类型和 QVariant 互相转换 想要能够使得自定义类型的对象和 QVariant 能够互相转换,自定义类型需要在类声明的头文件中使用宏 Q_DECLARE_METATYPE() 声明一下,告知 Qt 的 Meta System:
使用 QVariant::fromValue(customClassObject)
把自定义类型的对象转换为 QVariant 对象
使用 variantObject.value<CustomClass>()
把 QVariant 对象转换为自定义类型的对象
Adding a Q_DECLARE_METATYPE() makes the type known to all template based functions, including QVariant.
下面使用自定义类 User 和 QVaraint 互转为例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #ifndef USER_H #define USER_H #include <QString> #include <QVariant> #include <QMetaType> class User {public : User (int id = 50 ); int id; QString username; QString password; }; Q_DECLARE_METATYPE (User) #endif
1 2 3 4 5 #include "User.h" User::User (int id) : id (id) { }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <QDebug> #include <QVariant> #include "User.h" int main (int argc, char *argv[]) { Q_UNUSED (argc) Q_UNUSED (argv) User ali (33 ) ; QVariant var = QVariant::fromValue (ali); qDebug () << var.canConvert<User>(); User alex = var.value<User>(); qDebug () << alex.id; return 0 ; }
信号槽中使用自定义类型 如果 connect 的类型是 Qt::DirectConnection ,也就是同一个线程中使用,那么不需要做什么,自定义类型的对象可以直接在信号槽中作为参数,但是如果 connect 的类型是 Qt::QueuedConnection ,自定义类型除了使用宏 Q_DECLARE_METATYPE() 声明外,还必须调用 qRegisterMetaType 注册后才可以:
1 qRegisterMetaType<User>();
Adding a Q_DECLARE_METATYPE() makes the type known to all template based functions, including QVariant. Note that if you intend to use the type in queued signal and slot connections or in QObject’s property system, you also have to call qRegisterMetaType() since the names are resolved at runtime.
To use the type T in QVariant, using Q_DECLARE_METATYPE() is sufficient. To use the type T in queued signal and slot connections, qRegisterMetaType() must be called before the first connection is established.
Also, to use type T with the QObject::property() API, qRegisterMetaType() must be called before it is used, typically in the constructor of the class that uses T, or in the main() function.
QObject property 中使用自定义类型 *QObject::setProperty(const char name, const QVariant &value) 可以动态地存储数据,这样我们就不需要为了保存数据而定义很多变量了,使用 *QObject::property(const char name) 就能够取得存储的数据,是不是非常方便!
为了让 QObject 的 property 支持自定义类型的对象,自定义的类需要实现运算符 **QVariant()**,如下 User 的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #ifndef USER_H #define USER_H #include <QString> #include <QVariant> #include <QMetaType> class User {public : User (int id = 50 ); operator QVariant () const ; int id; QString username; QString password; }; Q_DECLARE_METATYPE (User)#endif
1 2 3 4 5 6 7 8 9 #include "User.h" User::User (int id) : id (id) { } User::operator QVariant () const { return QVariant::fromValue (*this ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <QDebug> #include <QVariant> #include "User.h" int main (int argc, char *argv[]) { Q_UNUSED (argc) Q_UNUSED (argv) User alex (33 ) ; QObject obj; obj.setProperty ("user" , alex); User ronnie = obj.property ("user" ).value<User>(); qDebug () << ronnie.id; return 0 ; }
QDataStream 序列化自定义类型的 QVariant 自定义类型的对象转换为 QVaraint 对象后,如果要使用 QDataStream 操作这个 varaint 的话,需要:
自定义类型实现 QDataStream& operator<<(QDataStream &stream, const CustomClass &obj)
自定义类型实现 QDataStream& operator>>(QDataStream &stream, CustomClass &obj)
使用 qRegisterMetaTypeStreamOperators 进行注册
任然以 User 为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #ifndef USER_H #define USER_H #include <QString> #include <QVariant> #include <QMetaType> #include <QDataStream> class User {public : User (int id = 50 , const QString &username = QString (), const QString &password = QString ()); friend QDataStream& operator <<(QDataStream &stream, const User &user); friend QDataStream& operator >>(QDataStream &stream, User &user); int id; QString username; QString password; }; Q_DECLARE_METATYPE (User)#endif
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include "User.h" User::User (int id, const QString &username, const QString &password) : id (id), username (username), password (password) { } QDataStream& operator <<(QDataStream &stream, const User &user) { stream << user.id << user.username << user.password; return stream; } QDataStream& operator >>(QDataStream &stream, User &user) { stream >> user.id >> user.username >> user.password; return stream; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <QDebug> #include <QVariant> #include <QByteArray> #include <QDataStream> #include "User.h" int main (int argc, char *argv[]) { Q_UNUSED (argc) Q_UNUSED (argv) qRegisterMetaTypeStreamOperators<User>(); QVariant aliVar = QVariant::fromValue (User (100 , "Ali" , "Secret" )); QByteArray buffer; QDataStream out (&buffer, QIODevice::WriteOnly) ; out << aliVar; QDataStream in (&buffer, QIODevice::ReadOnly) ; QVariant readedAliVar; in >> readedAliVar; User readedAli = readedAliVar.value<User>(); qDebug () << QString ("ID: %1, Username: %2, Password: %3" ) .arg (readedAli.id).arg (readedAli.username).arg (readedAli.password); return 0 ; }