c++ - 从 QSettings 读取自定义元类型数组

标签 c++ qt qvariant qsettings

我在从 QSetting 读取自定义元类型数据时遇到问题。 我有一个类:

class MusicOwner
{
public:
    MusicOwner() :
        songs_count(0),
        id(0)
    {}

    explicit MusicOwner(const Song &owner_radio);
    Song toOwnerRadio() const;

    static QList<MusicOwner> parseMusicOwnerList(const QVariant &request_result);

private:
    friend QDataStream &operator <<(QDataStream &stream, const VkService::MusicOwner &val);
    friend QDataStream &operator >>(QDataStream &stream, VkService::MusicOwner &val);
    friend QDebug operator<< (QDebug d, const MusicOwner &owner);

    int songs_count;
    int id;
    QString name;
    QString screen_name;
    QUrl photo;
};

Q_DECLARE_METATYPE(VkService::MusicOwner)

重载:

QDataStream &operator <<(QDataStream &stream, const VkService::MusicOwner &val)
{
    stream << val.id;
    stream << val.name;
    stream << val.songs_count;
    stream << val.screen_name;
    return stream;
}

QDataStream &operator >>(QDataStream &stream, VkService::MusicOwner &val)
{
    stream >> val.id;
    stream >> val.name;
    stream >> val.songs_count;
    stream >> val.screen_name;
    return stream;
}

QDebug operator <<(QDebug d, const VkService::MusicOwner &owner)
{
    d << "MusicOwner("
      << owner.id << ","
      << owner.name << ","
      << owner.songs_count << ","
      << owner.screen_name << ")";
    return d;
}

在程序开始的某个地方我调用:

qRegisterMetaTypeStreamOperators<MusicOwner>("MusicOwner");

为了读写,我使用两个函数: 保存工作正常,我保存的所有数据都出现在设置文件中。

void VkService::SaveBookmarks()
{
    TRACE;
    QSettings s;
    s.beginGroup(kSettingGroup);

    s.beginWriteArray("bookmarks");
    int index = 0;
    for (int i = 0; i < root_item_->rowCount(); ++i){
        auto item = root_item_->child(i);
        if (item->data(InternetModel::Role_Type).toInt() == Type_Bookmark){
            Song song = item->data(InternetModel::Role_SongMetadata).value<Song>();
            s.setArrayIndex(index);
            MusicOwner owner(song);
            qLog(Info) << "Save" << index << ":" << owner;
            s.setValue("owner", QVariant::fromValue(owner));
            ++index;
        }
    }
    s.endArray();
}

此函数存在问题,它的加载计数正确,但加载的是空的默认构造项。

void VkService::LoadBookmarks()
{
    QSettings s;
    s.beginGroup(kSettingGroup);

    int max = s.beginReadArray("bookmarks");
    for (int i = 0; i < max; ++i){
        s.setArrayIndex(i);
        MusicOwner owner = s.value("owner").value<MusicOwner>();
        qLog(Info) << "Load" << i << ":" << owner;
        AppendBookmarkFromRadio(root_item_, owner.toOwnerRadio());
    }
    s.endArray();
}

我将其重写为新项目进行测试,但它工作正常。 我花了两个小时来找出为什么这个变体可以正确读取数据而第一个变体却不能。 第一个变体的所有者正确转换。甚至两个变体中设置文件中的数据也是相同的。

#include <QCoreApplication>
#include <QDataStream>
#include <QDebug>
#include <QUrl>
#include <QSettings>
#include <QVariant>

class MusicOwner
{
public:
    MusicOwner() :
        songs_count(0),
        id(0)
    {}

private:
    friend QDataStream &operator <<(QDataStream &stream, const MusicOwner &val);
    friend QDataStream &operator >>(QDataStream &stream, MusicOwner &val);
    friend QDebug operator<< (QDebug d, const MusicOwner &owner);

public:
    int songs_count;
    int id;
    QString name;
    QString screen_name;
    QUrl photo;
};


QDataStream &operator <<(QDataStream &stream, const MusicOwner &val)
{
    stream << val.id;
    stream << val.name;
    stream << val.songs_count;
    stream << val.screen_name;
    return stream;
}

QDataStream &operator >>(QDataStream &stream, MusicOwner &val)
{
    stream >> val.id;
    stream >> val.name;
    stream >> val.songs_count;
    stream >> val.screen_name;
    return stream;
}

QDebug operator <<(QDebug d, const MusicOwner &owner)
{
    d << "MusicOwner("
      << owner.id << ","
      << owner.name << ","
      << owner.songs_count << ","
      << owner.screen_name << ")";
    return d;
}

Q_DECLARE_METATYPE(MusicOwner)

const QString kSettingGroup = "Group";

void Save() {
    QSettings s;
    s.beginGroup(kSettingGroup);

    s.beginWriteArray("bookmarks");
    int index = 0;
    for (int i = 0; i < 100; ++i){
        if (random() % 5 == 0) {
            s.setArrayIndex(index);
            MusicOwner owner;
            owner.id = i;
            owner.name ="Hello world";
            owner.songs_count = i * 2;
            owner.screen_name = "hello_world";

            s.setValue("owner", QVariant::fromValue(owner));
            qDebug() << "Saved" << i << ":" << owner;
            ++index;
        }
    }
    s.endArray();
    qDebug() << "Saved" << index << "elements";
}

void Load() {
    QSettings s;
    s.beginGroup(kSettingGroup);

    int max = s.beginReadArray("bookmarks");
    qDebug() << "To load" << max << "elements";

    for (int i = 0; i < max; ++i){
        s.setArrayIndex(i);
        MusicOwner owner = s.value("owner").value<MusicOwner>();
        qDebug() << "\tLoaded" << i << ":" << owner;
    }
    s.endArray();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qRegisterMetaTypeStreamOperators<MusicOwner>("MusicOwner");
    QSettings s;

    Load();
    Save();

    return a.exec();
}

也许您可以发现此变体中 QSettings 的工作差异?

最佳答案

您对示例中的命名空间一点也不小心。如果您实际上在非工作代码中使用了命名空间,那么您就无法创建不使用命名空间的“最小情况”。

以下可编译示例使用命名空间,并且在 Qt 4.8 和 5.1 中都能正常工作。请注意,这些设置默认情况下在 4.8 和 5.1 之间不可移植,我不知道这是一个错误还是一个功能。

#include <QCoreApplication>
#include <QDataStream>
#include <QDebug>
#include <QSettings>
#include <QVariant>

namespace VkService {

class MusicOwnerA
{
    friend QDataStream &operator <<(QDataStream &stream, const MusicOwnerA &val);
    friend QDataStream &operator >>(QDataStream &stream, MusicOwnerA &val);
    friend QDebug operator<< (QDebug d, const MusicOwnerA &owner);
public:
    MusicOwnerA() : id(0) {}
    int id;
    QString name;
};

QDataStream &operator <<(QDataStream &stream, const VkService::MusicOwnerA &val)
{
    stream << val.id;
    stream << val.name;
    return stream;
}

QDataStream &operator >>(QDataStream &stream, VkService::MusicOwnerA &val)
{
    stream >> val.id;
    stream >> val.name;
    return stream;
}

QDebug operator <<(QDebug d, const VkService::MusicOwnerA &owner)
{
    d << "VkService::MusicOwnerA("
      << owner.id << ","
      << owner.name << ")";
    return d;
}

}

Q_DECLARE_METATYPE(VkService::MusicOwnerA)

void Save() {
    QSettings s;
    s.beginWriteArray("bookmarks");
    int index = 0;
    for (int i = 0; i < 100; ++i){
        if (random() % 5 == 0) {
            s.setArrayIndex(index);
            VkService::MusicOwnerA owner;
            owner.id = i;
            owner.name ="Hello world";
            s.setValue("owner", QVariant::fromValue(owner));
            qDebug() << "Saved" << i << ":" << owner;
            ++index;
        }
    }
    s.endArray();
    qDebug() << "Saved" << index << "elements";
}

void Load() {
    QSettings s;
    int max = s.beginReadArray("bookmarks");
    qDebug() << "To load" << max << "elements";
    for (int i = 0; i < max; ++i){
        s.setArrayIndex(i);
        VkService::MusicOwnerA owner = s.value("owner").value<VkService::MusicOwnerA>();
        qDebug() << "\tLoaded" << i << ":" << owner;
    }
    s.endArray();
}

int main(int argc, char **argv)
{
    QCoreApplication a(argc, argv);
    a.setOrganizationDomain("16549302.stackoverflow.com");
    qRegisterMetaTypeStreamOperators<VkService::MusicOwnerA>("VkService::MusicOwnerA");
    Load();
    Save();
}

关于c++ - 从 QSettings 读取自定义元类型数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16549302/

相关文章:

c++ - 将 Qt 添加到 C-Socket 程序中?

c++ - QT - 如何从组合框中检索 QVariant 值?

c++ - 用 C++ 制作动画

c++ - 重新着色 SDL2 纹理

c++ - 调用 Singleton getInstance() 时出现 undefined symbol 错误

c++ - QTableView 在模型刷新后保留选择

windows - QImage抖动质量

long-integer - 如何将 unsigned long int 转换为 QVariant

qt - 从 QVariant 到整数和字符串

c++ - 在 Windows 环境中使用 C/C++ 联网