如何在Qt中使用自定义数据类型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Qt中使用自定义数据类型相关的知识,希望对你有一定的参考价值。

使用下面这个struct来做说明(这里不管是struct还是class都一样):

    struct Player

    int number;

    QString firstName;

    QString lastName;

    ;

    QVariant    
    为了能在QVariant中使用自定义数据类型做,需要使用Q_DECLARE_METATYPE()来向Qt的元系统声明这个自定义类型。如下列所示:

    struct Player

    ...

    ;

    Q_DECLARE_METATYPE(Player);

    在作为QVariant传递自定义数据类型时,需要使用QVariant::fromValue()或者qVariantFromValue:

    Player player;

    object->setProperty("property", QVariant::fromValue(player));

    为了更方便一点,你可以在自定义类型中定义一个QVariant() 类型转换符:

    struct Player

    ...

    operator QVariant() const

    return QVariant::fromValue(*this);

    ;

    这样我们便可以像下面这样使用了:

    Player player;

    object->setProperty("property", player);

    信号和槽    
    对于直接连接类型(默认情况下就是直接连接)而言,使用自定义数据类型做信号参数不需要做其他其他处理,就像内置数据类型一样:

    connect(sender, SIGNAL(playerCreated(const Player&)), receiver, SLOT(addPlayer(const Player&)));

    但在跨线程时如果你还这么做,编译器就会给出警告了:

    QObject::connect: Cannot queue arguments of type \'Player\'

    (Make sure \'Player\' is registered using qRegisterMetaType().)

    这时我们需要先注册Player:

    qRegisterMetaType<Player>("Player");  

    qRegisterMetaType<Player>( );   (上面那个是错误的,除非名字刚好和类名一样)

    connect(sender, SIGNAL(playerCreated(const Player&)), receiver, SLOT(addPlayer(const Player&)));

    QDebug    
    最好是能这样:

    qDebug() << player;

    而不是这样:

    qDebug() << "Player(" << player.number << "," << player.firstName << "," << player.lastName << ")";

    怎么做呢?我们需要对QDebug<<操作符重载一下:

    inline QDebug operator<<(QDebug debug, const Player& player)

    debug.nospace() << "Player("

    << player.number << ","

    << player.firstName << ","

    << player.lastName << ")";

    return debug.space();

    QDataStream    
    跟上面的QDebug很像,我们也需要重载一下<<操作符:

    inline QDataStream& operator<<(QDataStream& out, const Player& player)

    out << player.number;

    out << player.firstName;

    out << player.lastName;

    return out;

    inline QDataStream& operator>>(QDataStream& in, Player& player)

    in >> player.number;

    in >> player.firstName;

    in >> player.lastName;

    return in;

    QSettings

    QSettings 用QVariant保存键值,用QDataStream序列化自定义数据。(参考后面的variantToString函数)      
    为了能在QSettings中使用自定义数据类型,需要让Qt的元系统知道有此类型,就像上面介绍QVariant部分一样,另外还要提供相应的QDataStream操作符,还必须注册这个流操作符:

    qRegisterMetaTypeStreamOperators<Player>("Player");

    如此处理之后我们就可以像下面这样使用了:

    QSettings settings;

    Player player;

    settings.setValue("key", player);

    QSettings settings;

    Player player = value("key").value<Player>();

    参考:

    QString QSettingsPrivate::variantToString(const QVariant &v)    

    QString result;

    switch (v.type())
    case QVariant::Invalid:
    result = QLatin1String("@Invalid()");
    break;

    case QVariant::ByteArray:
    QByteArray a = v.toByteArray();
    result = QLatin1String("@ByteArray(");
    result += QString::fromLatin1(a.constData(), a.size());
    result += QLatin1Char(\')\');
    break;

    case QVariant::String:
    case QVariant::LongLong:
    case QVariant::ULongLong:
    case QVariant::Int:
    case QVariant::UInt:
    case QVariant::Bool:
    case QVariant::Double:
    case QVariant::KeySequence:
    result = v.toString();
    if (result.startsWith(QLatin1Char(\'@\')))
    result.prepend(QLatin1Char(\'@\'));
    break;
       
    #ifndef QT_NO_GEOM_VARIANT
    case QVariant::Rect:
    QRect r = qvariant_cast<QRect>(v);
    result += QLatin1String("@Rect(");
    result += QString::number(r.x());
    result += QLatin1Char(\' \');
    result += QString::number(r.y());
    result += QLatin1Char(\' \');
    result += QString::number(r.width());
    result += QLatin1Char(\' \');
    result += QString::number(r.height());
    result += QLatin1Char(\')\');
    break;

    case QVariant::Size:
    QSize s = qvariant_cast<QSize>(v);
    result += QLatin1String("@Size(");
    result += QString::number(s.width());
    result += QLatin1Char(\' \');
    result += QString::number(s.height());
    result += QLatin1Char(\')\');
    break;

    case QVariant::Point:
    QPoint p = qvariant_cast<QPoint>(v);
    result += QLatin1String("@Point(");
    result += QString::number(p.x());
    result += QLatin1Char(\' \');
    result += QString::number(p.y());
    result += QLatin1Char(\')\');
    break;
       
    #endif // !QT_NO_GEOM_VARIANT

    default:    
    #ifndef QT_NO_DATASTREAM
    QByteArray a;

    QDataStream s(&a, QIODevice::WriteOnly);
    s.setVersion(QDataStream::Qt_4_0);
    s << v;

    result = QLatin1String("@Variant(");
    result += QString::fromLatin1(a.constData(), a.size());
    result += QLatin1Char(\')\');    
    #else
    Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");    
    #endif
    break;

    return result;    

    qsetting为了让保存的ini文件能和ascii兼容,所以

    我们将ini文件中的键值读入到 QVariant 中,需要两个步骤:

    因为文件内的一些字符被转义了,比如 "\\x1234\\t\\0"等,所以需要 unescape

    从 unescape 后的字符串构造出 QVariant

    当将QVariant写入文件时:

    将 QVariant 转换成字符串

    处理字符串中的特殊字符,即 escape

参考技术A 和一般使用类和结构体一样的 参考技术B 就是C++

以上是关于如何在Qt中使用自定义数据类型的主要内容,如果未能解决你的问题,请参考以下文章

QT 信号与槽 中传递自定义数据类型

qt信号槽接收不到的情况(自定义数据类型+多线程)

qt修正参数怎么调用自定义函数

如何在 TypeScript 中创建自定义类型

如何将 Qt 属性与自定义类一起使用?

自定义数据类型使用QVariant转换的方法