Russian Qt Forum
Сентябрь 30, 2024, 10:34 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: QSettings  (Прочитано 8997 раз)
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« : Декабрь 22, 2008, 22:48 »

Использую QSettings для нескольких программ - т.е. они хранят натсройки в одном файле.
Система Ubuntu 8.04/
Заметил такую вещь - одна программа читает текстовое поле в файле настроек (в моем случае INI файл) выглядит так:

Text_1="Some Text"

другая программа сохраняет настройки своего окошка (геометрию) - выглядит так:

Geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x1\0\0\0\0\0\xd9\0\0\0M\0\0\x4\x13\0\0\x2\xac\0\0\0\xdd\0\0\0Q\0\0\x3\xfa\0\0\x2\xa8\0\0\0\0\0\0)

Послето того как вторая пересохраняет параметры своего окошка - текст текстового поля становится нечитаем - что то типа такого

Text_1=\xd0\xad\xd0\x94\x39\xd0\x9c

- видимо его тоже пересохраняет как ByteArray - как сделать чтобы этого не происходило (т.к. человеческим глазом там ничего потом не разобрать - а это требуется)
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #1 : Декабрь 23, 2008, 00:09 »

Нашел в ассистенте такой код:

bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map);
 bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map);

 
Код
C++ (Qt)
int main(int argc, char *argv[])
{
    const QSettings::Format XmlFormat =
            QSettings::registerFormat("xml", readXmlFile, writeXmlFile);
 
    QSettings settings(XmlFormat, QSettings::UserSettings, "MySoft",
                       "Star Runner");
 
    ...
}

вроде это адаптация QSettings для работы с XML файлами - нигде не могу найти и не могу понять как реализовывать функции:

bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map);
 bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map);

я получая управление в них не имею понятия ни о том какая настройка хочет прочитаться - и открытые устройства как Binary --- зачем?

Дошел до этого т.к. понял что INI айл ублюдство в моем случае - оно становится таковым как только надо хранить вложенные таблицы в качестве настроек....
« Последнее редактирование: Декабрь 23, 2008, 22:31 от pastor » Записан
Rcus
Гость
« Ответ #2 : Декабрь 23, 2008, 22:09 »

Судя по src/corelib/io/qsettings*.* это ограничение пользовательских форматов настроек (чтение/запись должны производиться разом). Чтобы реализовать свой xml формат настроек достаточно использовать QDomDocument::setContent для чтения и ::toByteArray для записи, а вот как вы будете хранить структуру настроек, разные типы (в том числе пользовательские) уже зависит целиком от вашей фантазии.
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #3 : Январь 12, 2009, 21:15 »

с QtXml работаю и все ОК - все что совсем невмоготу храню в XML - но все же хочется добиться УДОБОЧИТАЕМОГО ДЛЯ ЧЕЛОВЕКА хранения данных через QSettings - в виндовс когда оно хранится в реестре - то все ок т.к. древовидная структура, но в Linux эти ini - не вариант для параметров большой вложенности...

В общем мне не до конца понятно как переопределять функции

bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map);
bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map);

Получается что все настройки должны прочитаться разом когда объект QSettings создастся и записаться разом когда сохраниться - метож sync() ??

Если да то при определении этих функций в момент записи "QSettings::SettingsMap &map" будет содержать все необходимые параметры для записи а в случае определения readXmlFile
я наоборот доложен заполнить его?

Еще интересно в каком месте системы создасться XML файл кот. я буду писать - опять же Я сам все это определяю?
« Последнее редактирование: Январь 12, 2009, 21:23 от break » Записан
ритт
Гость
« Ответ #4 : Январь 12, 2009, 21:36 »

на все вопрос - "да" Улыбающийся

QSettings::SettingsMap (это QVariantMap) - проблем с разбором и пониманием быть не должно...

> в каком месте системы создасться XML файл
имя(или полный путь/имя) укажешь сам при создании. альтернативно можешь указать дефолтовые пути для своего формата (QSettings::setPath(...))
Записан
vaprele07
Гость
« Ответ #5 : Январь 13, 2009, 03:50 »

сделал бы кто-нибудь хмл2склайт в би-деревьях и выложил бы это в гпл я бы был так счастлив  Строит глазки

по теме смотри: http://www.cloanto.com/specs/ini.html кодировка... все станет ясно почему...
Записан
break
Гипер активный житель
*****
Offline Offline

Сообщений: 846


Просмотр профиля
« Ответ #6 : Январь 31, 2009, 19:06 »

Наконец то появилось время написал маленький класс для хранения чтения настроек через QSettings но через XML, вдруг кому пригодиться:

XmlSettings.h:
Код:
#include <QString>
#include <QSettings>

class QDomDocument;
class QDomElement;
class QIODevice;

class CXmlSettings
{
QSettings * m_pSettings;
public:
CXmlSettings( QString fname = "" );
~CXmlSettings();

inline QSettings& settings() const { return *m_pSettings; };

private:
static bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map);
static bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map);
static void processWriteKey( QDomDocument& doc, QDomElement& domElement, QString key, const QVariant& value );
static void processReadKey( QString key, QSettings::SettingsMap &map, QDomElement& domElement );
};

XmlSettings.cpp:
Код:

#include "XmlSettings.h"
#include "FileUtils.h"

#include <QDebug>

CXmlSettings::CXmlSettings( QString fname )
{
if ( fname == "" )
fname = dataPath() + "../Settings/" + appBaseName() + ".xml";

static const QSettings::Format XmlFormat = QSettings::registerFormat("xml", readXmlFile, writeXmlFile);

m_pSettings = new QSettings( fname, XmlFormat );
};

CXmlSettings::~CXmlSettings()
{
delete m_pSettings;
};

bool CXmlSettings::readXmlFile(QIODevice &device, QSettings::SettingsMap &map)
{
qDebug() << " -----readXmlSettings----- ";

QDomDocument doc("");
if ( !doc.setContent( &device ) ) return false;

QDomElement root = doc.documentElement();

processReadKey( "", map, root );

return true;
};

bool CXmlSettings::writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map)
{
qDebug() << " -----writeXmlSettings----- ";

QDomDocument doc("");
QDomElement root = doc.createElement("Main");
doc.appendChild(root);

QMapIterator<QString, QVariant> i(map);
while ( i.hasNext() )
{
i.next();

QString  sKey = i.key();
QVariant value = i.value();
processWriteKey( doc, root, sKey, i.value() );
};

QDomNode xmlNode = doc.createProcessingInstruction("xml","version=\"1.0\" encoding=\"\"");
doc.insertBefore(xmlNode, doc.firstChild());

QTextStream out( &device );
doc.save(out, 4);

return true;
};

void CXmlSettings::processWriteKey( QDomDocument& doc, QDomElement& domElement, QString key, const QVariant& value )
{
int slashPos = key.indexOf( '/' );

// переданный ключ является параметром
if ( slashPos < 0 )
{
// не пишем в конфиг параметр size (является ограничением - нельзя исп. пар-тр с таким именем)
if ( key == "size" ) return;
domElement.setAttribute( key, value.toString() );
return;
};

// получение имени группы соответствующей xml ноде
QString groupName = key.left( slashPos );
// если в качестве имени использован числовой параметр - это табличная строка, преобразуем ее в row_?
if ( groupName.toInt() )
{
groupName = "row_" + groupName;
domElement.toElement().setAttribute("table", "1");
};

// поиск/создание ноды соответствующей ключу
QDomElement groupElement;
QDomNodeList findedNodes = domElement.elementsByTagName( groupName );

if ( !findedNodes.count() ) // Заданный элемент-нода не найден - создаем его
{
groupElement = doc.createElement( groupName );
domElement.appendChild( groupElement );
}
else
{
Q_ASSERT( findedNodes.count() == 1 ); // в конфигах не должно быть несколько элементов с одинаковым именем
groupElement = findedNodes.item(0).toElement();
};

// готовим обрезанную часть ключа
key = key.right( key.size() - slashPos - 1 );

// продолжение обработки (создание/поиск групп) - пока не найдется параметр
processWriteKey( doc, groupElement, key, value );
};

void CXmlSettings::processReadKey( QString key, QSettings::SettingsMap &map, QDomElement& domElement )
{

QDomNamedNodeMap namedNodeMap = domElement.attributes();

// Добавление всех атрибутов элемента в качестве значений
for (int i = 0; i < namedNodeMap.count(); ++i)
{
QString name = namedNodeMap.item( i ).toAttr().name();
QString value = namedNodeMap.item( i ).toAttr().value();
map.insert( key + name, value );
};

QDomNodeList nlChild = domElement.childNodes();

// если узел является таблицей - то все дети строки
bool isTable = domElement.attribute("table", "0").toInt();
// создаем доп. элемент size равный числу детей (необходим для QSettings - beginArray)
if ( isTable )
map.insert( key + "size", nlChild.count() );

// проход по всем детям
for (int i = 0; i < nlChild.count(); ++i)
{
QString childName = nlChild.item(i).toElement().tagName();
if ( childName.contains("row_") )
childName = childName.right( childName.size() - 4 );

QString subKey = key + childName + "/";
QDomElement subElement = nlChild.item(i).toElement();
processReadKey( subKey, map, subElement );
};
};

Ограничение - нельзя использовать теги "table" и "size" в качестве "своих" атрибутов, чтобы компонент понял что в ноде таблица - тег "table" должен быть 1. Все строки такой табличной ноды должны иметь имя тега "row_1", "row_2" и т.д. - Это все важно при создание конфига человеком - при создание из программы все автоматически формируется как надо.

Доступ к стандартному QSettings - через ф-ю settings()
Поддерживается все что было в QSettings (вроде) Group/Array и т.д.

Чтобы скомпилировался нужно опр-ть 2 функции appBaseName() - у меня возвращает имя запускаемого файла без расширения, dataPath() - путь к папке в которой хр-ся ресурсы программы (Б.Д. и т.д.).

В целом должны пониматься вот такие xml:
Код:
<?xml version="1.0" encoding=""?>
<Main root_val_1="1" root_val_2="2" >
    <FirstChild paramIP="192.168.1.1" >
        <FirstChildTable table="1" >
            <row_1 pluginName="XXX" />
            <row_2 pluginName="XXX_2" />
        </FirstChildTable>
    </FirstChild>
    <SecondChild>
        <SomeParamsGroup Enabled="1" Visible="1" />
    </SecondChild>
</Main>

В конструкторе можно передовать имя файла настроек (с полным путем).
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.257 секунд. Запросов: 22.