Хранение описания всех контролов формы, обработчиков событий, настроек в БД
Направьте в какую сторону копать.
Есть идея хранить описания всех контролов, обработчиков событий, настроек программы в Базе Данных и при запуске приложения строить форму динамически.
Это удобно, когда нужно сделать апдейт, не обновляя экзешник.
Кто-нибудь сталкивался?
В принципе как хранить описания контролов более менее кажется интуитивно понятным, но вот как хранить код??? А самое главное как его потом исполнять без компиляции???
Заранее благодарен.
2)Изменяемый код лучше компилировать в отдельные бинарники (часто dll-библиотеки для этого используют, но можно и объектники). Схема примерно такая: например, код обработчика события вызывает внешнюю функцию. Внешняя функция хранится откомпилированной в dll-ке. Если нужно поменять ее реализацию (не трогайте ее название и параметры), то просто меняете код исходника dll для этой ф-ции и dll заново компилируете. Т.е. не всю программу придется перекомпилировать, а только dll. Пользователю в качестве обновления потребуется лишь dll-ка.
3)Существует еще такая вещь как сериализация. Тут много нюансов. Можете почитать в сети для общего развития.
Геометрию контролов хранить чертовски просто. Например в INI файле.
я себе множество вариантов сохранения всего делал когда-то. Где-то валяется ещё для D7 сохранение всех published в INI через RTTI.
Код:
procedure TIniAppGeometry.WriteBounds(ASection, AIdent: string;
var AControl: TControl);
var
R: ^TRect;
S: TStream;
begin
try
if Assigned(AControl) then
begin
New(R);
R^ := AControl.BoundsRect;
S := TMemoryStream.Create;
try
S.WriteBuffer(R^, SizeOf(R^));
S.Position := 0;
WriteBinaryStream(ASection, AIdent, S);
finally
FreeAndNil(S);
end;
end;
except
end;
end;
var AControl: TControl);
var
R: ^TRect;
S: TStream;
begin
try
if Assigned(AControl) then
begin
New(R);
R^ := AControl.BoundsRect;
S := TMemoryStream.Create;
try
S.WriteBuffer(R^, SizeOf(R^));
S.Position := 0;
WriteBinaryStream(ASection, AIdent, S);
finally
FreeAndNil(S);
end;
end;
except
end;
end;
Код:
procedure TIniAppGeometry.MagicWriteBounds(var AControl: TControl;
ASection, APrefix: string);
var
I: Integer;
C: TControl;
begin
WriteBounds(ASection, APrefix + AControl.Name, AControl);
for I := 0 to Pred(AControl.ComponentCount) do
begin
if AControl.Components[I].Name <> '' then
begin
C := TControl(AControl.Components[I]);
WriteBounds(ASection, APrefix + C.Name, C);
end;
end;
end;
ASection, APrefix: string);
var
I: Integer;
C: TControl;
begin
WriteBounds(ASection, APrefix + AControl.Name, AControl);
for I := 0 to Pred(AControl.ComponentCount) do
begin
if AControl.Components[I].Name <> '' then
begin
C := TControl(AControl.Components[I]);
WriteBounds(ASection, APrefix + C.Name, C);
end;
end;
end;
Код:
procedure TIniAppGeometry.ReadBounds(ASection, AIdent: string;
var AControl: TControl);
var
R: ^TRect;
S: TStream;
begin
try
S := TMemoryStream.Create;
New(R);
try
ReadBinaryStream(ASection, AIdent, S);
S.Position := 0;
S.ReadBuffer(R^, SizeOf(R^));
AControl.BoundsRect := R^;
finally
Dispose(R);
S.Free;
end;
except
end;
end;
var AControl: TControl);
var
R: ^TRect;
S: TStream;
begin
try
S := TMemoryStream.Create;
New(R);
try
ReadBinaryStream(ASection, AIdent, S);
S.Position := 0;
S.ReadBuffer(R^, SizeOf(R^));
AControl.BoundsRect := R^;
finally
Dispose(R);
S.Free;
end;
except
end;
end;
Цитата: sadovoya
1)Хранить настройки программы отдельно от нее -- нормальная практика. Смело используйте.
2)Изменяемый код лучше компилировать в отдельные бинарники (часто dll-библиотеки для этого используют, но можно и объектники). Схема примерно такая: например, код обработчика события вызывает внешнюю функцию. Внешняя функция хранится откомпилированной в dll-ке. Если нужно поменять ее реализацию (не трогайте ее название и параметры), то просто меняете код исходника dll для этой ф-ции и dll заново компилируете. Т.е. не всю программу придется перекомпилировать, а только dll. Пользователю в качестве обновления потребуется лишь dll-ка.
3)Существует еще такая вещь как сериализация. Тут много нюансов. Можете почитать в сети для общего развития.
2)Изменяемый код лучше компилировать в отдельные бинарники (часто dll-библиотеки для этого используют, но можно и объектники). Схема примерно такая: например, код обработчика события вызывает внешнюю функцию. Внешняя функция хранится откомпилированной в dll-ке. Если нужно поменять ее реализацию (не трогайте ее название и параметры), то просто меняете код исходника dll для этой ф-ции и dll заново компилируете. Т.е. не всю программу придется перекомпилировать, а только dll. Пользователю в качестве обновления потребуется лишь dll-ка.
3)Существует еще такая вещь как сериализация. Тут много нюансов. Можете почитать в сети для общего развития.
А если понадобится вдруг добавить новую функциональность?
Хотелось бы обходится без перекомпила экзешника
Лучше задумайтесь о принципах организации своего кода для удобного повторного применение в будущих программах и о модифицируемости/расширяемости кода. Имею ввиду иерархии классов и прочий ООП, а также грамотное размещение кода по единицам трансляции. А компилировать не такой уж гемор, особенно если вы построите программу модульно, а не одним экзешником.
По поводу хранения настрек/свойств. Был в Delphi 6 удобный класс TIniFile. Он предоставляет средства для записи и чтения в ini-файл (по-сути обычный текстовый файл). Пример работы:
Код:
uses .... inifiles;
....
procedure TMainForm.ReadParams; // Чтение данных пользователя из ini-файла
Var
IniFile:TIniFile;
begin
IniFile:=TIniFile.Create(Path+'UserData.ini');
Top:=IniFile.ReadInteger('Главная форма','Координата верха',100);
Left:=IniFile.ReadInteger('Главная форма','Координата левой стороны',130);
Combobox1.Text:=IniFile.ReadString('Данные','Длина волны','1064');
Combobox6.Text:=IniFile.ReadString('Данные','Длина резонатора','100');
Combobox4.Text:=IniFile.ReadString('Данные','Фокус линзы','-1000');
Combobox5.Text:=IniFile.ReadString('Данные','Координата линзы','50');
Combobox2.Text:=IniFile.ReadString('Данные','R глух. зеркала','-1500');
Combobox3.Text:=IniFile.ReadString('Данные','R вых. зеркала','150');
ComboBox7.Text:=IniFile.ReadString('Масштаб','Диаметр линзы','1');
LabeledEdit2.Text:=IniFile.ReadString('Диапазон линз','P1','7');
LabeledEdit3.Text:=IniFile.ReadString('Диапазон линз','P2','10');
CheckBox1.Checked:=IniFile.ReadBool('Флажки','TEM00',True);
CheckBox2.Checked:=IniFile.ReadBool('Флажки','TEM01',False);
CheckBox3.Checked:=IniFile.ReadBool('Флажки','TEM11',True);
CheckBox4.Checked:=IniFile.ReadBool('Флажки','TEM02',False);
CheckBox5.Checked:=IniFile.ReadBool('Флажки','TEM12',True);
CheckBox6.Checked:=IniFile.ReadBool('Флажки','TEM22',False);
IniFile.Free;
end;
procedure TMainForm.WriteParams; // Запись в ini-файл пользовательских данных
Var
IniFile:TIniFile;
begin
IniFile:=TIniFile.Create(Path+'UserData.ini'); // создаем переменную
IniFile.WriteInteger('Главная форма','Координата верха',Top);
IniFile.WriteInteger('Главная форма','Координата левой стороны',Left);
IniFile.WriteString('Данные','Длина волны',ComboBox1.Text);
IniFile.WriteString('Данные','Длина резонатора',ComboBox6.Text);
IniFile.WriteString('Данные','Фокус линзы',ComboBox4.Text);
IniFile.WriteString('Данные','Координата линзы',ComboBox5.Text);
IniFile.WriteString('Данные','R глух. зеркала',ComboBox2.Text);
IniFile.WriteString('Данные','R вых. зеркала',ComboBox3.Text);
IniFile.WriteString('Масштаб','Диаметр линзы',ComboBox7.Text);
IniFile.WriteString('Диапазон линз','P1',LabeledEdit2.Text);
IniFile.WriteString('Диапазон линз','P2',LabeledEdit3.Text);
IniFile.WriteBool('Флажки','TEM00',CheckBox1.Checked);
IniFile.WriteBool('Флажки','TEM01',CheckBox2.Checked);
IniFile.WriteBool('Флажки','TEM11',CheckBox3.Checked);
IniFile.WriteBool('Флажки','TEM02',CheckBox4.Checked);
IniFile.WriteBool('Флажки','TEM12',CheckBox5.Checked);
IniFile.WriteBool('Флажки','TEM22',CheckBox6.Checked);
IniFile.Free;
end;
....
procedure TMainForm.ReadParams; // Чтение данных пользователя из ini-файла
Var
IniFile:TIniFile;
begin
IniFile:=TIniFile.Create(Path+'UserData.ini');
Top:=IniFile.ReadInteger('Главная форма','Координата верха',100);
Left:=IniFile.ReadInteger('Главная форма','Координата левой стороны',130);
Combobox1.Text:=IniFile.ReadString('Данные','Длина волны','1064');
Combobox6.Text:=IniFile.ReadString('Данные','Длина резонатора','100');
Combobox4.Text:=IniFile.ReadString('Данные','Фокус линзы','-1000');
Combobox5.Text:=IniFile.ReadString('Данные','Координата линзы','50');
Combobox2.Text:=IniFile.ReadString('Данные','R глух. зеркала','-1500');
Combobox3.Text:=IniFile.ReadString('Данные','R вых. зеркала','150');
ComboBox7.Text:=IniFile.ReadString('Масштаб','Диаметр линзы','1');
LabeledEdit2.Text:=IniFile.ReadString('Диапазон линз','P1','7');
LabeledEdit3.Text:=IniFile.ReadString('Диапазон линз','P2','10');
CheckBox1.Checked:=IniFile.ReadBool('Флажки','TEM00',True);
CheckBox2.Checked:=IniFile.ReadBool('Флажки','TEM01',False);
CheckBox3.Checked:=IniFile.ReadBool('Флажки','TEM11',True);
CheckBox4.Checked:=IniFile.ReadBool('Флажки','TEM02',False);
CheckBox5.Checked:=IniFile.ReadBool('Флажки','TEM12',True);
CheckBox6.Checked:=IniFile.ReadBool('Флажки','TEM22',False);
IniFile.Free;
end;
procedure TMainForm.WriteParams; // Запись в ini-файл пользовательских данных
Var
IniFile:TIniFile;
begin
IniFile:=TIniFile.Create(Path+'UserData.ini'); // создаем переменную
IniFile.WriteInteger('Главная форма','Координата верха',Top);
IniFile.WriteInteger('Главная форма','Координата левой стороны',Left);
IniFile.WriteString('Данные','Длина волны',ComboBox1.Text);
IniFile.WriteString('Данные','Длина резонатора',ComboBox6.Text);
IniFile.WriteString('Данные','Фокус линзы',ComboBox4.Text);
IniFile.WriteString('Данные','Координата линзы',ComboBox5.Text);
IniFile.WriteString('Данные','R глух. зеркала',ComboBox2.Text);
IniFile.WriteString('Данные','R вых. зеркала',ComboBox3.Text);
IniFile.WriteString('Масштаб','Диаметр линзы',ComboBox7.Text);
IniFile.WriteString('Диапазон линз','P1',LabeledEdit2.Text);
IniFile.WriteString('Диапазон линз','P2',LabeledEdit3.Text);
IniFile.WriteBool('Флажки','TEM00',CheckBox1.Checked);
IniFile.WriteBool('Флажки','TEM01',CheckBox2.Checked);
IniFile.WriteBool('Флажки','TEM11',CheckBox3.Checked);
IniFile.WriteBool('Флажки','TEM02',CheckBox4.Checked);
IniFile.WriteBool('Флажки','TEM12',CheckBox5.Checked);
IniFile.WriteBool('Флажки','TEM22',CheckBox6.Checked);
IniFile.Free;
end;
В новых версиях Дельфи возможно появились более продвинутые классы, например, для работы через XML.
Еще стандартный путь - хранение в реестре и чтение из него. Для "portable"- программ не подходит (те, которые работают с флешки и все свое держат в собственной папке). Кроме того потребуется позаботиться об уборке мусора из реестра при удалении программы с компа.
Реестром вообще лучше не пользоваться, особенно если хочется мультиплатформенную программу сделать.