Чтение массива пользовательских метатипов из 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();
}

Я переписал его в новый проект для тестирования, но он работает FINE.
Я трачу два часа, чтобы выяснить, почему этот вариант правильно читает данные, а первый — нет.
Владелец в первом варианте конвертирует правильно. Даже данные в файле настроек в обоих вариантах одинаковы.

#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 в этих вариантах?

0

Решение

Вы совсем не осторожны со своими пространствами имен в примере. Вы не можете создать «минимальный случай», в котором не используются пространства имен, если вы фактически используете их в своем нерабочем коде.

Следующий компилируемый пример использует пространства имен и отлично работает как в 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();
}
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]