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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: QSettings. Автоматическое чтение в переменные разных типов.  (Прочитано 5263 раз)
PheeL
Гость
« : Апрель 07, 2009, 10:12 »

Господа, хотелось бы попросить совета относительно элегантного алгоритма чтения сохранённых параметров в глобальные переменные различного типа.
Есть куча глобальных переменных разных типов(как простых - int, char; так и "сложных" - QSize, QPalette). Хотелось бы одним циклом их все прочитать за раз из реестра/файла инициализации с помощью объекта класса QSettings.
В документации, к сожалению, рассматривается только лишь способ чтения по-одному элементу с вызовом метода конверсии типа. Это не годится. У меня есть некий вариант решения, но он не очень красив.
« Последнее редактирование: Апрель 07, 2009, 12:28 от PheeL » Записан
Rcus
Гость
« Ответ #1 : Апрель 07, 2009, 11:24 »

Если они глобальные то метаинформацию о типе получить не получится. Если их загнать в потомок QObject и прописать свойства, то прочитать можно, только клея там будет больше чем при ручном переборе.
Альтернативное решение это KConfigXT. Технология беспредельно крута: легкое связывание с диалогами настройки, генерация кода из простого XML описания, только проблема в том что поддерживаются не все типы /*мне лично не хватило поддержки QByteArray*/, и приходится тащить kdelibs/core+ui (а под Windows еще дополнительные зависимости и проблемы со стабильностью).
Записан
-QT-
Гость
« Ответ #2 : Апрель 16, 2009, 16:47 »

Это не поможет ?
Код
C++ (Qt)
T QextSettings::readValue( const QString &group, const QString &name, T &defaultValue )
{
   QextSettings::beginGroup( group );
   T myValue = qvariant_cast<T>( QextSettings::value( name, defaultValue ) );
   QextSettings::endGroup();
   return myValue;
}
Записан
PheeL
Гость
« Ответ #3 : Апрель 17, 2009, 06:26 »

Это не поможет ?
Ммм... В данном примере, мне не очень нравится что значение возвращается через стек. Это хорошо, когда типы маленькие. А возвращать переменные, типа QByteArray будет уже накладно. К тому же тут, насколько я понимаю, тип переменной нужно знать на этапе компиляции, а это немного проблематично в плюсах(это, насколько знаю, будет доступно только в компиляторах поддерживающих спецификации C++ 0x - decltype).
Приведу свой вариант реализации:
Код
C++ (Qt)
//globals.h
 
enum {
   GET,
   SET
};
 
enum {
   OK,
   ERR_UNKNOWN_TYPE,
   ERR_UNKNOWN_MODE,
};
 
typedef struct settings_s {
   void      *val_ptr;
   int        val_type;
   QString    val_name;
} settings_t;
 
//Global variables
extern int           app_locale;
extern int           cur_scr_mode;
extern QString       debug_str;
 

Код
C++ (Qt)
//globals.cpp
 
#include "globals.h"
 
int     app_locale         = RU;
int     cur_scr_mode       = SCREEN;
QString debug_str          = "Debug string";
 

Код
C++ (Qt)
//main.cpp
 
#include "globals.h"
 
settings_t settings_arr[] = {
       (void *)&app_locale,        QVariant::Int,          "app_locale",
       (void *)&cur_scr_mode,      QVariant::Int,          "cur_scr_mode",
       (void *)&debug_str,         QVariant::String,       "debug_str",
       NULL
};
 
//Load and save application settings
//---------------------------------------------------------------
void MyClass::Settings( int mode )
{
QSettings   settings( "MyProg", "Settings" );
settings_t  *settings_arr_p = settings_arr;
 
   do {
       assert( SettingVal( &settings, settings_arr_p, mode ) == OK );
       settings_arr_p++;
   } while( settings_arr_p->val_ptr != NULL );
}
 
//Get and set application setting
//---------------------------------------------------------------
int MyClass::SettingVal( QSettings *settings_p, settings_t *settings_arr_p, int mode )
{
   switch( settings_arr_p->val_type ) {
       case QVariant::Int:
           if( mode == GET ) {
               *(int *)settings_arr_p->val_ptr =
                   settings_p->value(settings_arr_p->val_name, *(int *)settings_arr_p->val_ptr).toInt();
           }
           else if( mode == SET ) {
               settings_p->setValue(settings_arr_p->val_name, *(int *)settings_arr_p->val_ptr);
           }
           else return ERR_UNKNOWN_MODE;
           break;
 
       case QVariant::String:
           if( mode == GET ) {
               *(QString *)settings_arr_p->val_ptr =
                   settings_p->value(settings_arr_p->val_name, *(QString *)settings_arr_p->val_ptr).toString();
           }
           else if( mode == SET ) {
               settings_p->setValue(settings_arr_p->val_name, *(QString *)settings_arr_p->val_ptr);
           }
           else return ERR_UNKNOWN_MODE;
           break;
 
       default:
           return ERR_UNKNOWN_TYPE;
//            break;
   }
   return OK;
}
 

Он, правда, наверное слишком C based, но я с плюсами только начинаю знакомиться.
В данном варианте мне категорически не нравится буквально тройное описание глобальных переменных - в заголовочном, в реализации, да ещё и в массиве переменных! Отсюда очень большая вероятность ошибок при правках глобальных переменных. Есть предложения как улучшить код? Или другие варианты.
« Последнее редактирование: Апрель 17, 2009, 06:29 от PheeL » Записан
ритт
Гость
« Ответ #4 : Апрель 26, 2009, 03:06 »

а чем не угодил QVariant? или я что-то упустил/не так понял?
Записан
PheeL
Гость
« Ответ #5 : Апрель 26, 2009, 12:49 »

а чем не угодил QVariant? или я что-то упустил/не так понял?
Я не хочу хранить глобальные переменные в типе QVariant. Мне их все-равно придётся потом приводить к другому типу при работе с ними. Поэтому зачем тратить на этот тип память и время?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #6 : Апрель 26, 2009, 16:24 »

данных сколько? сдается мне, что у тебя обычная проблема при переходе с си - байтосчитание. Оно имеет смысл, если пишешь маленькие программки на чистом std с++. Qt само по себе кушает достаточно много (другое дело, что при разрастании проекта память растет гораздо медленней нежели по линейной зависимости). Таким образом, экономить память на QVariant'ах глупо. Раз.
Если ты глянешь исходники QVariant, то увидишь, что данных там мало - там много ф-ий для работы с ними. Данные же объеденены в union, самый большой тип - это QAtomicInt (если не ошибаюсь, то это массив из 4х интов, если я правильные сорцы глядел). Всё остальное сводится к тому же void*. Два
Записан
PheeL
Гость
« Ответ #7 : Апрель 26, 2009, 17:32 »

данных сколько? сдается мне, что у тебя обычная проблема при переходе с си - байтосчитание. Оно имеет смысл, если пишешь маленькие программки на чистом std с++. Qt само по себе кушает достаточно много (другое дело, что при разрастании проекта память растет гораздо медленней нежели по линейной зависимости). Таким образом, экономить память на QVariant'ах глупо. Раз.
Спорить не стану. Да, основная моя деятельность - это программирование микроконтроллеров на чистом С. Думаю, понятно какой это  на меня накладывает отпечаток как на программиста. Поэтому я не стану лезть в чужой храм со своим уставом. Тут действительно больше возникает вопрос обоснованности выбора того или иного метода работы при реализации программы. Просто не хотелось на ходу при работе с переменными дёргать методы конверсии типа. Хотя, да, вызовов будет немного.
Если ты глянешь исходники QVariant, то увидишь, что данных там мало - там много ф-ий для работы с ними. Данные же объеденены в union, самый большой тип - это QAtomicInt (если не ошибаюсь, то это массив из 4х интов, если я правильные сорцы глядел). Всё остальное сводится к тому же void*. Два
Исходников не глядел - посмотрю. Просто в умных книжках тоже достаточно предвзятое отношение было к этому типу. Правда там глобальнее вопрос рассматривался, а в моей ситуации я имею частный случай при котором может быть и оправдано использование данного типа.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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