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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Чтение/запись INI файла  (Прочитано 10012 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Декабрь 10, 2012, 21:33 »

Добрый день

Навеяно этим http://www.prog.org.ru/index.php?topic=23719.msg167660#msg167660
Как обычно, обсуждение архитектуры - ну нельзя сказать чтобы "бесполезно", но капитально застряет на специфике задачи. Возможно есть смысл "поархитектурить" на вещи которая всем известна.

Есть диалог, общее число опций напр 60, рассованы напр по 5 табам. Нужно читать/писать все параметры в INI файл, допустим 1 табка 1 секция + какие-то общие параметры что в UI находятся вне рамок таба. Делать бинарную сериализацию не хочется т.к. диалог часто меняется. Ручное редактирование текстовика вполне возможно, поэтому имена параметров в INI должны быть внятными. Для пользователя выглядит так: нажал Save - задал файл, сохранил. Нажал Load, выбрал файл. Появился вспомогательный диалог где можно указать какие табки загружать. Ok - загрузили, UI соответственно изменилось. Если какие-то опции отсутствуют в INI или записаны там с ошибкой - сообщить

Полагаю что для продвинутых Qt пользователей такая задачка не составляет особой сложности. Какие структуры данных, классы и взаимодействия нужно реализовать?

Спасибо
Записан
V1KT0P
Гость
« Ответ #1 : Декабрь 10, 2012, 22:13 »

Я бы попробовал json. Очень он мне нравится своей простотой и гибкостью.
Записан
Bepec
Гость
« Ответ #2 : Декабрь 10, 2012, 22:40 »

Я пользуюсь QSettings.
Менеджер настроек представляет собой класс, который все эти данные соотносит, сохраняет и загружает. В результате на выходе ini файл, дружелюбный пользователю. Добавление/изменение настройки = изменение в функции сохранения/загрузки класса.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Декабрь 11, 2012, 10:32 »

Я бы попробовал json. Очень он мне нравится своей простотой и гибкостью.
В смысле любой уровень вложенности массивов/контейнеров? Хорошее дело, но здесь одного уровня (по табкам) вполне хватает. А вот возможность редактировать текстовик желательна.  Да и json ридер "надо изыскивать" и прикручивать (пусть их и много).

Я пользуюсь QSettings.
Менеджер настроек представляет собой класс, который все эти данные соотносит, сохраняет и загружает. В результате на выходе ini файл, дружелюбный пользователю. Добавление/изменение настройки = изменение в функции сохранения/загрузки класса.
Прошу показать каким образом, напр в псевдокоде. Все 60 параметров расписывать не надо, так, пару-тройку
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #4 : Декабрь 11, 2012, 12:11 »

Прошу показать каким образом, напр в псевдокоде. Все 60 параметров расписывать не надо, так, пару-тройку
Как-то так:
Код
C++ (Qt)
QSettings s( "options.ini", QSettings::IniFormat );
foreach( QWidget* tw, dialog->findChildren< QTabWidget* >() )
{
   foreach( QWidget* w, tw->findChildren< QWidget* >() )
   {
        if( qobject_cast< QLabel* >( w ) )
            continue;
        QString key = dialog->objectName() + '/' + tw->objectName() + '/' + w->objectName();
        if( QLineEdit* le = qobject_cast< QLineEdit* >( w ) )
        {
            if( is_saving )
            {
                s.setValue( key, le->text() );
            }  else
            {
                QVariant v = s.value( key );
                if( v.isValid() )
                    le->setText( v.toString() );
                else
                    qWarning( w->objectName() + ": invalid value" );
            }
        }
        else if( QSpinBox* sb = qobject_cast< QSpinBox* >( w ) )
        {
            if( is_saving )
            {
                s.setValue( key, sb->value() );
            }  else
            {
                QVariant v = s.value( key );
                if( v.isValid() )
                    sb->setValue( v.toInt() );
                else
                    qWarning( w->objectName() + ": invalid value" );
            }
        }
        else if( ... )
        {
        }
   }
}
 
Update: добавил группировку по табам)
« Последнее редактирование: Декабрь 11, 2012, 13:08 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
Bepec
Гость
« Ответ #5 : Декабрь 11, 2012, 12:13 »

Необходима соответственно небольшая подготовка - слот у объектов, отдающий параметры или передача из объектов параметров менеджеру
Код:
// QList<QPair<QVariant, QVariant>> valueList_;
QSettings setting(sbSettingsFileName_, QSettings::IniFormat);
setting.setIniCodec("Windows-1251");
for(int i = 0; i < valueList_.size();i++)
{
setting.setValue( valueList_[i].first(), valueList_[i].second());
}

В принципе нужна ещё обвязка для распределения настроек по классам. (я так делаю) Или же как упоминал - получение настроек из менеджера.

Псевдокод фиговый если честно Улыбающийся На деле есть ещё разделение по группам beginGroup. Распределение ведётся по строке first(QVariant)где закодировано название/класс виджета + название настройки.

PS извиняюсь если сумбурно моё изложение.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #6 : Декабрь 11, 2012, 12:17 »

2 Bepec
Цитировать
« Ответ #5 : Сегодня в 13:13:13 »
Хорошее время ты выбрал для поста)
Записан

Qt 5.11/4.8.7 (X11/Win)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Декабрь 13, 2012, 09:47 »

В принципе нужна ещё обвязка для распределения настроек по классам. (я так делаю) Или же как упоминал - получение настроек из менеджера.
Ну так рассказывайте что за менеджер, а то что Вы показываете цикл for который ни о чем не говорит  Улыбающийся

Как-то так:
Код
C++ (Qt)
QSettings s( "options.ini", QSettings::IniFormat );
foreach( QWidget* tw, dialog->findChildren< QTabWidget* >() )
...
 
Хороший, боевой вариант. С точки зрения реализации я бы не лез в ближний бой if/else, а сделал бы это расширяемым (псевдокод)
Код
C++ (Qt)
for (int i = 0; i < converters.size(); ++i)
if (converter[i]->Data2UI(widget, settings, prefix, &errCode)) break;
 
Чтобы если появился какой-то хитрый контрол - спокойно долить это в в контейнер converters. Но это сути не меняет. Привлекательна общность, для любого диалога надо только назначить имена (это так и так надо делать) - и работает.

Однако как же так - ведь это смешивает "бизнес-логику" (как говорит Akon) с UI. Ну действительно, чуть другая задача - мы сначала выбираем ini файл, а потом уж показываем диалог - или вообще не показываем. Тогда не видно как воспользоваться написанным, придется городить еще один "параллельный" вариант

Я понимаю что то легко говорить, мол, "не смешивайте", а доходит до дела - так куда что девается  (и как быстро находятся само-оправдания Улыбающийся)
Записан
Bepec
Гость
« Ответ #8 : Декабрь 13, 2012, 13:04 »

У меня к сожалению нет возможности "выдрать" код из проекта. Слишком эмм... много зависимостей.

Но структура проста - имеется у менеджера список подключенных виджетов, в который они сами добавляются. Потом они передают настройки и он их сохраняет в группу, название которой содержит класс виджета и его objectName. Ну и в обратном направлении так же - проверяется наличие в списке загруженных настроек и тогда отдаются.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Декабрь 14, 2012, 14:01 »

У меня к сожалению нет возможности "выдрать" код из проекта. Слишком эмм... много зависимостей.

Но структура проста - имеется у менеджера список подключенных виджетов, в который они сами добавляются. Потом они передают настройки и он их сохраняет в группу, название которой содержит класс виджета и его objectName. Ну и в обратном направлении так же - проверяется наличие в списке загруженных настроек и тогда отдаются.
Что-то не видно обычной словоохотливости Улыбающийся Ну ладно, у каждого есть места где гордиться нечем, но которые (как-то) работают - и слава богу. Это нормально.

А вот как это решалось в шейдерах 3ds (как сейчас - не знаю, но во всяком случае так было). Конструктор ниже (с переменным числом параметров) очень скромный, бывали в неск раз больше.  Впрочем главная идея (дескриптор параметра) мне кажется верной и сейчас.

Код
C++ (Qt)
static ParamBlockDesc2 strata_param_blk ( strata_params, _T("params"),  0, &StrataDesc,
P_AUTO_CONSTRUCT + P_AUTO_UI, PBLOCK_REF,
//rollout
IDD_PANEL, IDS_PARAMS, 0, 0, NULL,
// params
 
pb_objsize, _T("Object Size"), TYPE_FLOAT, P_ANIMATABLE, IDS_SPIN_SIZE,
p_default, 1.0f,
p_range, 0.0f, 1000000.0f,
p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_EDIT_SIZE, IDC_SPIN_SIZE, 1.0f,
end,
 
pb_height, _T("Height"), TYPE_FLOAT, P_ANIMATABLE, IDS_SPIN_HEIGHT,
p_default, 1.0f,
p_range, -1000000.0f, 1000000.0f,
p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_EDIT_HEIGHT, IDC_SPIN_HEIGHT, 1.0f,
end,
 
pb_combo_scheme, _T("Use Preset"), TYPE_INT,   0, IDS_FW_PRESET,
p_default, 0,
p_ui, TYPE_INTLISTBOX, IDC_COMBO_PRESET,  0,
p_accessor, &comboPBAccessor,
end,
 
pb_combo_browse, _T("Browse Style"), TYPE_INT,   0, IDS_FW_PRESET,
p_default, 0,
p_ui, TYPE_INTLISTBOX, IDC_COMBO_BROWSE,  3,   IDS_BRW_NRML, IDS_BRW_SAVCOL, IDS_BRW_COLONLY,
p_accessor, &comboPBAccessor,
end,
 
pb_combo_grad, _T("Gradient"), TYPE_INT,   0, IDS_FW_GRADIENT,
p_default, 0,
p_ui, TYPE_INTLISTBOX, IDC_COMBO_COLOR,   4,   IDS_GRAD1, IDS_GRAD2, IDS_GRAD3, IDS_GRAD4,
p_accessor, &comboPBAccessor,
end,
 
// gradient count, colors & keys
pb_numkey, _T("NumKey"), TYPE_INT,   0, IDS_FW_GRADIENT, end,
pb_selkey, _T("SelKey"), TYPE_BOOL,   0, IDS_FW_GRADIENT, end,
 
pb_color0, _T("Color0"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR1, end,
pb_color1, _T("Color1"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR2, end,
pb_color2, _T("Color2"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR3, end,
pb_color3, _T("Color3"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR4, end,
pb_color4, _T("Color4"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR5, end,
pb_color5, _T("Color5"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR6, end,
pb_color6, _T("Color6"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR7, end,
pb_color7, _T("Color7"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR8, end,
pb_color8, _T("Color8"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR9, end,
pb_color9, _T("Color9"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR10, end,
pb_color10, _T("Color10"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR11, end,
pb_color11, _T("Color11"), TYPE_RGBA,   P_ANIMATABLE, IDS_COLOR12, end,
 
pb_X0, _T("KeyX0"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS1, p_range, 0.0f, 1.0f, end,
pb_X1, _T("KeyX1"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS2, p_range, 0.0f, 1.0f, end,
pb_X2, _T("KeyX2"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS3, p_range, 0.0f, 1.0f, end,
pb_X3, _T("KeyX3"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS4, p_range, 0.0f, 1.0f, end,
pb_X4, _T("KeyX4"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS5, p_range, 0.0f, 1.0f, end,
pb_X5, _T("KeyX5"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS6, p_range, 0.0f, 1.0f, end,
pb_X6, _T("KeyX6"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS7, p_range, 0.0f, 1.0f, end,
pb_X7, _T("KeyX7"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS8, p_range, 0.0f, 1.0f, end,
pb_X8, _T("KeyX8"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS9, p_range, 0.0f, 1.0f, end,
pb_X9, _T("KeyX9"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS10, p_range, 0.0f, 1.0f, end,
pb_X10, _T("KeyX10"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS11, p_range, 0.0f, 1.0f, end,
pb_X11, _T("KeyX11"), TYPE_FLOAT,   P_ANIMATABLE, IDS_OFS12, p_range, 0.0f, 1.0f, end,
 
// coordinates
pb_coords, _T("coords"), TYPE_REFTARG, P_OWNERS_REF, IDS_COORDS,
p_refno, COORD_REF,
end,
 
pb_graymode, _T("GrayMODE"), TYPE_BOOL,   0, IDS_GRAYMODE,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_CHECKGRAY,
end,
 
end
);
 
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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