Mega Code Archive

 
Categories / Delphi / Examples
 

How to save (object) configuration data easily

Title: How to save (object) configuration data easily unit Unit_UserConfig; ////////////////////////////////////////////////////////////////////// /// /// Unit zur vereinfachten Speicherung von User-Daten /// /// Mittels Save werden die Eigenschaften ALLER Child-Komponenten einer /// Komponente gespeichert. /// Load holt diese dann wieder /// /// In Datei speichern /// UserConfig:=TUserConfig.Create(0); //Nur auf Festplatte speichern /// aufruf z.B. SaveToFile (GroupBox1,'configuratio.cfg'); /// LoadFromFile(GroupBox1,'configuratio.cfg'); /// /// In Speicher ablegen /// (Damit kann z.B eine Undo-Funktion f¨¹r Optionen realisiert werden) /// UserConfig:=TUserConfig.Create(10); //Pl?tze zur Speicherung bereithalten /// aufruf z.B. SaveToFile (Form1,5); //Auf Platz 5 speichern /// LoadFromFile(Form1,5); //von Platz 4 laden /// /// ///(c) 2005 Borg@Sven-of-Nine.de /// ///Beispielprogramm unter www.Sven-of-Nine.de /// ////////////////////////////////////////////////////////////////////// interface uses Classes; type TUserConfig = class(TObject) private { Private-Deklarationen } //Direkter Zugriff auf Eigenschaften //set properties using winapi function IsProperty(Obj: TObject; sProp: string): Boolean; function SetProperty(Obj: TObject; sProp: string; vValue: Variant): Boolean; function HasAncestor(Child: TComponent; Name: string): Boolean; public { Public-Deklarationen } constructor Create(MaxMemory: Integer = 10); destructor Destroy(); override; //Komponenten in Datei schreiben //save/load components to/from file function SaveToFile(Component: TComponent; sFilename: string): Boolean; function LoadFromFile(Component: TComponent; sFilename: string): Boolean; //Komponenten in Speicher schreiben (UNDO-Funktion) //save/load components to/from mem function SaveToMemory(Component: TComponent; Index: Integer): Boolean; function LoadFromMemory(Component: TComponent; Index: Integer): Boolean; end; implementation uses Windows, SysUtils, Controls, Forms, TypInfo; var aMemStream: array of TMemoryStream; ////////////////////////////////////////////////////////////////////// /// Konstruktor und Destruktor ////////////////////////////////////////////////////////////////////// constructor TUserConfig.Create(MaxMemory: Integer = 10); var iIndex: Integer; begin //Alle angeforderten Speicherstreams initialisieren //initialize memorystreams if (MaxMemory 255) then MaxMemory := 255; try SetLength(aMemStream, MaxMemory); for iIndex := 0 to MaxMemory - 1 do begin aMemStream[iIndex] := TMemoryStream.Create; end; finally end; end; destructor TUserConfig.Destroy(); var iIndex: Integer; begin //Alle angeforderten Speicherstreams freimachen //free all for iIndex := 0 to Length(aMemStream) - 1 do begin aMemStream[iIndex].Free; end; SetLength(aMemStream, 0); end; ////////////////////////////////////////////////////////////////////// /// Pr¨¹fen, ob ein Object die gew¨¹nschte Eigenschaft hat /// Check for properties ////////////////////////////////////////////////////////////////////// function TUserConfig.IsProperty(Obj: TObject; sProp: string): Boolean; var plList: tPropList; iIndex1: Integer; iIndex2: Integer; begin Result := False; //Alle verf¨¹gbaren Properties holen //get properties iIndex2 := GetPropList(PTypeInfo(Obj.ClassInfo), [tkUnknown, tkVariant, tkInteger, tkInt64, tkFloat, tkString, tkWString, tkLString, tkChar, tkWChar, tkEnumeration, tkSet, tkClass, tkMethod, tkArray, tkDynArray, tkRecord, tkInterface], @plList); //nach der gew¨¹nschten suchen //search for the wanted iIndex1 := 0; while (iIndex1 ) do begin if plList[iIndex1].Name = sProp then begin Result := True; iIndex1 := iIndex2; end; Inc(iIndex1); end; end; ////////////////////////////////////////////////////////////////////// /// Eine Egenschaft direkt setzen /// set properties ////////////////////////////////////////////////////////////////////// function TUserConfig.SetProperty(Obj: TObject; sProp: string; vValue: Variant): Boolean; begin if (IsProperty(Obj, sProp)) then begin SetPropValue(Obj, sProp, vValue); Result := True; end else begin Result := False; end; end; ////////////////////////////////////////////////////////////////////// /// Nach einem Vorfahr mit dem Namen "Name" suchen /// check for ancestor named "Name" ////////////////////////////////////////////////////////////////////// function TUserConfig.HasAncestor(Child: TComponent; Name: string): Boolean; var cWork: TComponent; begin Result := False; cWork := Child; while (cWork.HasParent) do begin //Eltern holen cWork := cWork.GetParentComponent; //Sind die Eltern die gesuchten ? if (cWork.Name = Name) then begin //Dann Suche beenden Result := True; break; end; end; cWork := nil; end; ////////////////////////////////////////////////////////////////////// /// Save all components to disk /// alle komponenten in datei speichern ////////////////////////////////////////////////////////////////////// function TUserConfig.SaveToFile(Component: TComponent; sFilename: string): Boolean; var hFile: THandle; Stream: THandleStream; iIndex: Integer; sName: string[255]; cWork: TComponent; begin Result := False; //Datei auf jeden Fall immer neu erzeugen //Create File hFile := FileCreate(sFilename); if (hFile 0) then begin //Die Hauptkomponente finden (das Formular) //Find parent cWork := Component; while (cWork.HasParent) do begin cWork := cWork.GetParentComponent; end; //Stream erzeugen //Create stream Stream := THandleStream.Create(hFile); try //Und los //enumerate all for iIndex := 0 to cWork.ComponentCount - 1 do begin //Ist es ein Win-Control und eine Nachfahre der gew¨¹nschten Componente? //save only TWinControls and childs of Component if (cWork.Components[iIndex] is TWinControl) and (HasAncestor(cWork.Components[iIndex], Component.Name)) then begin //Hier ein paar Ausnahmen //some exceptions if (cWork.Components[iIndex].ClassName 'TFlatTitlebar') and (cWork.Components[iIndex].ClassName 'TFlatSpinEd1itInteger') then begin //Erst den Namen //save name first sName := cWork.Components[iIndex].Name; Stream.Write(sName, Length(sName) + 1); //Und dann die Komponente hinterher //and component Stream.WriteComponent(cWork.Components[iIndex]); end; end; end; Result := True; finally //Fertig //done Stream.Free; end; //close handle FileClose(hFile); end; cWork := nil; end; ////////////////////////////////////////////////////////////////////// /// load all components from disk /// alle komponenten aus datei laden ////////////////////////////////////////////////////////////////////// function TUserConfig.LoadFromFile(Component: TComponent; sFilename: string): Boolean; var hFile: THandle; Stream: THandleStream; iIndex: Integer; sName: string[255]; iName: Integer; cWork: TComponent; begin Result := False; //Date ?ffnen //open read hFile := FileOpen(sFilename, fmOPENREAD); if (hFile 0) then begin //Das die Hauptkomponente finden (das Formular) cWork := Component; while (cWork.HasParent) do begin cWork := cWork.GetParentComponent; end; //Stream erzeugen //create stream Stream := THandleStream.Create(hFile); try //Vorne anfangen //from the beginning Stream.Position := 0; //Und kpl. durchwurstem //the whole file while (Stream.Position .Size) do begin //erstes byte des namens //first byte of Name Stream.read(sName[0], 1); //Gr??e rausholen //get size iName := Byte(sName[0]); //Und den ganzen Namen lesen //Read the whole name Stream.read(sName[1], iName); //Object holen //get object try //Nach dem namen suchens //search for the name for iIndex := 0 to cWork.ComponentCount - 1 do begin if (cWork.Components[iIndex].Name = sName) then begin //Bei allem, was Checked hat, dies erst auf FALSE // setzen //Uncheck all "checkables" SetProperty(cWork.Components[iIndex], 'Checked', False); //Und dann erst laden //load Stream.ReadComponent(cWork.Components[iIndex]); end; end; except end; end; finally //done Stream.Free; end; FileClose(hFile); end; cWork := nil; end; ////////////////////////////////////////////////////////////////////// /// Save all components to memory /// alle komponenten in speicher schreiben ////////////////////////////////////////////////////////////////////// function TUserConfig.SaveToMemory(Component: TComponent; Index: Integer): Boolean; var iIndex: Integer; sName: string[255]; cWork: TComponent; begin Result := False; if (Index 0) or (Index = Length(aMemStream)) then Exit; try //Die Hauptkomponente finden (das Formular) cWork := Component; while (cWork.HasParent) do begin cWork := cWork.GetParentComponent; end; for iIndex := 0 to cWork.ComponentCount - 1 do begin if (cWork.Components[iIndex] is TWinControl) and (HasAncestor(cWork.Components[iIndex], Component.Name)) then begin if (cWork.Components[iIndex].ClassName 'TFlatTitlebar') and (cWork.Components[iIndex].ClassName 'TFlatSpinEd1itInteger') then begin sName := Component.Components[iIndex].Name; aMemStream[Index].Write(sName, Length(sName) + 1); aMemStream[Index].WriteComponent(cWork.Components[iIndex]); end; end; end; Result := True; finally cWork := nil; end; end; ////////////////////////////////////////////////////////////////////// /// load components[index] from memory /// komponenten[index] aus speicher lesen ////////////////////////////////////////////////////////////////////// function TUserConfig.LoadFromMemory(Component: TComponent; Index: Integer): Boolean; var iIndex: Integer; sName: string[255]; iName: Integer; cWork: TComponent; begin Result := False; if (Index 0) or (Index = Length(aMemStream)) then Exit; try cWork := Component; while (cWork.HasParent) do begin cWork := cWork.GetParentComponent; end; aMemStream[Index].Position := 0; while (aMemStream[Index].Position [Index].Size) do begin aMemStream[Index].read(sName[0], 1); iName := Byte(sName[0]); aMemStream[Index].read(sName[1], iName); try for iIndex := 0 to cWork.ComponentCount - 1 do begin if (cWork.Components[iIndex].Name = sName) then begin SetProperty(cWork.Components[iIndex], 'Checked', False); aMemStream[Index].ReadComponent (cWork.Components[iIndex]); end; end; except end; end; Result := True; finally cWork := nil; end; end;