Внешний конфиг формы

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Внешний конфиг формы

Сообщение Voltag » 25.10.2018 22:08:37

Здравствуйте!

Хочу настройки окна(формы "Form1") вынести в файл
И чтобы я мог рукам или другой программой залезть в конфиг и подправить.

(пример: config_window.txt )
Код: Выделить всё
//[biSystemMenu,biMinimize,biMaximize,biHelp]
BorderIcons = [biSystemMenu] 
//fsNormal,  fsSplash, fsStayOnTop,  fsSystemStayOnTop
FormStyle =
//bsSizeable, bsSingle, bsDialog, bsNone
BorderStyle = 
Height = 100
Top =
Width =
Left = 30
Caption = "Привет мир"


код который выставляет настройки:
Код: Выделить всё
uses  ... TypInfo
...
var  p : PPropInfo;
//это кусок из цикла, который обходит файл конфигурации
//sKey - это название свойства (string)
//sVal - это значение свойства (string)
//к примеру Caption = "Привет мир"
//sKey = Caption
//sVal = "Привет мир"
...

if sVal <> '' then //если нет значения у переменной файле, то ничего не меняем, оставляем настройки формы по умолчанию
begin
        p := GetPropInfo(Form1, sKey); //получаем PPropInfo для sKey, для проверки на НАЛИЧИЕ свойства (мало ли что я наваяю руками)
        if Assigned(p) then begin //Проверка на существование, если есть значение sKey  продолжаем
             
            if lib.IsInteger(sVal) then begin //эта функция проверки на число, внутри её - Val, и код читается хорошо
                SetInt64Prop(Form1, sKey, IntToStr(sVal])); //Поскольку мы убедились что это значение инт, то пишем его как инт
                 //По хорошему я должен был получить руками "тип свойства" из описания класса.
             //Хотя можно и из класса в который хочу писать. И потом смотреть, что вообще можно писать, это я int хочу,
             //а может низя int
                 //Но пользоваться этим я буду , и как-нибудь прослежу, хотя надо конечно нормально написать
            end
           else if Copy(sVal,0,1) = '"' then begin //Лошарский признак строки, если первый символ двойная кавычка, значит строка
                SetStrProp(Form1, sKey, Copy(sVal,1, Length(sVal)-2)); //Пишем строку "Caption", вырезая первую и последнюю двойную кавычку               
         end
         else if (sVal = 'true') or (sVal = 'false') then begin
                    //Сдесь должна быть обработка булевых, я предполагаю что их надо писать как int 0 и 1, и проблем вроде не должно возникнуть, наверно...
            end else begin
                     //*****************************************************************************
                     // Здесь должна располагаться строчка обработки объектов
                // к примеру
                //sKey = BorderIcons
                //sVal = [biSystemMenu,biMinimize,biMaximize,biHelp]
                // А вот тут располагается МОЙ вопрос
                     // Проблему опишу ниже, вне кода
                //*****************************************************************************
            end;

        end;
end;               


Мне необходимо создать объект из строки
Это нужно для вот такой функции:
procedure SetObjectProp(
Instance: TObject;
const PropName: string;
Value: TObject
);

Итак вот строка конфига:
BorderIcons = [biSystemMenu,biMinimize,biMaximize,biHelp]
или вот:
FormStyle = bsSingle

теоретически, насколько я понимаю, должно получиться что-то типа(без переменных)
Код: Выделить всё
  SetObjectProp(Form1, 'BorderIcons', TBorderIcons('[biSystemMenu,biMinimize,biMaximize,biHelp]'));

Это всё работать не будет, т.к. я должен передать нормальный объект с нормальными свойствами, а не строку

Может мне надо взять, к примеру, копию Form1.BorderIcons как обычный объект, занулить его,
и потом как-то магически перенсети все свойства...

В общем я не знаю что мне делать. Совсем.

примечание: через if не интересно:
Код: Выделить всё
Form1.BorderIcons:=[];
if Pos(sVal, 'biSystemMenu') > 0 then Form1.BorderIcons:= Form1.BorderIcons+[biSystemMenu];
if Pos(sVal, 'biMinimize') > 0   then Form1.BorderIcons:= Form1.BorderIcons+[biMinimize];
if Pos(sVal, 'biMaximize') > 0   then Form1.BorderIcons:= Form1.BorderIcons+[biMaximize];
if Pos(sVal, 'biHelp') > 0       then Form1.BorderIcons:= Form1.BorderIcons+[biHelp];   


Спасибо, что дочитали до конца =)

С уважением
Voltag
новенький
 
Сообщения: 29
Зарегистрирован: 02.04.2008 03:49:33

Re: Внешний конфиг формы

Сообщение zoltanleo » 25.10.2018 22:41:40

Voltag писал(а):Хочу настройки окна(формы "Form1") вынести в файл ... Мне необходимо создать объект из строки
Это нужно для вот такой функции:

По-моему, ты пытаешься изобрести велосипед взамен имеющихся ini- и xml-файлов :)

Посмотри исходники TRxIniPropStorage и TRxXMLPropStorage из библиотеки RxLib Алекса Логунова
https://svn.code.sf.net/p/lazarus-ccr/s ... s/rx/trunk
Аватара пользователя
zoltanleo
постоялец
 
Сообщения: 457
Зарегистрирован: 17.10.2013 10:55:01

Re: Внешний конфиг формы

Сообщение Voltag » 26.10.2018 00:27:17

to zoltanleo
Спасибо за ответ, времени не так много, отвечать буду по чуть чуть

итак, первое что пришло в голову использовать(посмотреть) нативный компонент (о котором я не знал, но спасибо zoltanleo) и он есть
http://wiki.freepascal.org/TXMLPropStorage/ru

По поводу работы: немного покрутив, работать заставил... НО
Код: Выделить всё
//Простой пример
Form1.Caption:=IniPropStorage1.StoredValue['Caption'];

//Обращаю внимание, ручное приведение типов, я тоже это могу
Form1.Width:=StrToInt(IniPropStorage1.StoredValue['Width']);
//я могу так-же указать Width как строку, а не как параметр
//я могу просто указать Width=400 в конфиге и мне не надо перекомпилировать проект чтобы изменить свойство формы
//хотя можно конечно отфонтанировать кодом и прописать значения всей формы, но это плохое решение

//Приведу код из компонета (имею ввиду ручное чтение/запись):
procedure TCustomPropertyStorage.ReadRect(const Ident: string;
  out ARect: TRect; const Default: TRect);
begin
  ARect.Left:=ReadInteger(Ident+'Left',Default.Left);
  ARect.Top:=ReadInteger(Ident+'Top',Default.Top);
  ARect.Right:=ReadInteger(Ident+'Right',Default.Right);
  ARect.Bottom:=ReadInteger(Ident+'Bottom',Default.Bottom);
end; 


Я допускаю, что что-то не заметил, хотя я думаю об этом написали бы в документации

По ссылке я не нашёл TRxIniPropStorage хотя, я искал после долго рабочего дня.
Завтра поищу получше.
Voltag
новенький
 
Сообщения: 29
Зарегистрирован: 02.04.2008 03:49:33

Re: Внешний конфиг формы

Сообщение zub » 26.10.2018 00:51:10

ЕМНИП форму можно создать из внешней lfm, лишь бы используемые контролы были зареганы в бинарнике
zub
долгожитель
 
Сообщения: 2884
Зарегистрирован: 14.11.2005 23:51:26

Re: Внешний конфиг формы

Сообщение zoltanleo » 26.10.2018 01:40:18

Voltag писал(а):По поводу работы: немного покрутив, работать заставил... НО

Честно говоря, я так и не понял, с какими критериями нужен компонент. Я на дельфях одно время пользовался NiceSettings. Можешь глянуть на реализацию по ссылке.
Аватара пользователя
zoltanleo
постоялец
 
Сообщения: 457
Зарегистрирован: 17.10.2013 10:55:01

Re: Внешний конфиг формы

Сообщение Voltag » 27.10.2018 02:28:22

уже час ночи, а я ещё работу не закончил =) ... а я обещал отписываться
to zub
я посмотрел бегло, надо смотреть код более конкретно,
я имею ввиду код чтения формы, спасибо за совет

to zoltanleo
работает в D7, вот собственно код, который за это отвечает:
Код: Выделить всё
var
  Comp: TComponent;
  CompName, PropName, PropValue: string;
....
try
          PropName := Copy(s, i + 1, Length(s));
          if (FStoreTarget = stRegistry)
            then PropValue := Reg.ReadString(s)
            else PropValue := Ini.ReadString(Owner.Name, s, '');
          if (PropValue <> '')
//магическая строчка
            then SetPropValue(Comp, PropName, PropValue);
        except
          // Hide Exception
        end;


капнём дальше, пришлось искать глобальным поиском по всем файлам d7

D:\Borland\Delphi7\Source\Rtl\Common\ObjAuto.pas
procedure SetPropValue(Instance: TObject; PropInfo: PPropInfo; const Value: Variant);
немного не то

нам надо это:
D:\Borland\Delphi7\Source\Rtl\Common\TypInfo.pas
Код: Выделить всё
procedure SetPropValue(Instance: TObject; const PropName: string; const Value: Variant);

  function RangedValue(const AMin, AMax: Int64): Int64;
  begin
    Result := Trunc(Value);
    if (Result < AMin) or (Result > AMax) then
      raise ERangeError.CreateRes(@SRangeError);
  end;

var
  PropInfo: PPropInfo;
  TypeData: PTypeData;
  DynArray: Pointer;
begin
  // get the prop info
  PropInfo := GetPropInfo(Instance, PropName);
  if PropInfo = nil then
    PropertyNotFound(PropName)
  else
  begin
    TypeData := GetTypeData(PropInfo^.PropType^);

    // set the right type
    case PropInfo.PropType^^.Kind of
      tkInteger, tkChar, tkWChar:
        if TypeData^.MinValue < TypeData^.MaxValue then
          SetOrdProp(Instance, PropInfo, RangedValue(TypeData^.MinValue,
            TypeData^.MaxValue))
        else
          // Unsigned type
          SetOrdProp(Instance, PropInfo,
            RangedValue(LongWord(TypeData^.MinValue),
            LongWord(TypeData^.MaxValue)));
      tkEnumeration:
        if VarType(Value) = varString then
          SetEnumProp(Instance, PropInfo, VarToStr(Value))
        else if VarType(Value) = varBoolean then
          // Need to map variant boolean values -1,0 to 1,0
          SetOrdProp(Instance, PropInfo, Abs(Trunc(Value)))
        else
          SetOrdProp(Instance, PropInfo, RangedValue(TypeData^.MinValue,
            TypeData^.MaxValue));
      tkSet:
        if VarType(Value) = varInteger then
          SetOrdProp(Instance, PropInfo, Value)
        else
          SetSetProp(Instance, PropInfo, VarToStr(Value));
      tkFloat:
        SetFloatProp(Instance, PropInfo, Value);
      tkString, tkLString:
        SetStrProp(Instance, PropInfo, VarToStr(Value));
      tkWString:
        SetWideStrProp(Instance, PropInfo, VarToWideStr(Value));
      tkVariant:
        SetVariantProp(Instance, PropInfo, Value);
      tkInt64:
        SetInt64Prop(Instance, PropInfo, RangedValue(TypeData^.MinInt64Value,
          TypeData^.MaxInt64Value));
     tkDynArray:
      begin
        DynArrayFromVariant(DynArray, Value, PropInfo^.PropType^);
        SetOrdProp(Instance, PropInfo, Integer(DynArray));
      end;
    else
      raise EPropertyConvertError.CreateResFmt(@SInvalidPropertyType,
        [PropInfo.PropType^^.Name]);
    end;
  end;
end;


Я не буду комментировать в коде ... устал, но видно что идёт определение типа и идут записи конкретных типов

теперь лазарус (и как я её пропустил):
SetPropValue
https://lazarus-ccr.sourceforge.io/docs ... value.html

выдержка из документации:
Description
Due to missing Variant support, this function is not yet implemented; it is provided for Delphi compatibility only.
перевод:
Из-за отсутствия поддержки Variant эта функция еще не реализована; он предоставляется только для совместимости с Delphi.

В общем я узнал всё, что хотел

Простите за много кода, вдруг пригодится кому-то

Спасибо за помощь
Voltag
новенький
 
Сообщения: 29
Зарегистрирован: 02.04.2008 03:49:33


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 21

Рейтинг@Mail.ru