2005. december 10., szombat

How to save and load the captions of all components on a form to / from a text file


Problem/Question/Abstract:

I'm using a component which is able to save the caption of components to a textfile and then retrieve it again. This works quite nice since if one wants another language one can just change some captions and load the desired language. The only problem is that it is using only the well known Windows controls and is also checking if a component is of a certain type. Of course I want to be able to use it for all components, so how would I be able to check all the components on a form for caption properties (even if it is e.g. in a item of a component) without having to do type checking etc.?

Answer:

You can use functions from the TypInfo unit. You'll need a GetPropInfo to get information about the property, GetStrProp and SetStrProp functions to read and set a new caption for components. The example below is a component which can save the captions of all components on a form to the text file and load them back after the form was loaded. There is also a design time component editor which you need to save and load captions (see a popup menu over the component).

{The main component}
TMyCaptionReader = class(TComponent)
protected
  FFileName: string;
  procedure Loaded; override;
public
  constructor Create(AOwner: TComponent); override;
  procedure ReadCaptions;
  procedure WriteCaptions;
published
  property FileName: string read FFileName write FFileName;
end;

{The component editor}
TMyCaptionReaderEditor = class(TDefaultEditor)
public
  procedure ExecuteVerb(Index: Integer); override;
  function GetVerb(Index: Integer): string; override;
  function GetVerbCount: Integer; override;
end;

{ ... }

procedure TMyCaptionReaderEditor.ExecuteVerb(Index: Integer);
begin
  case Index of
    0: TMyCaptionReader(Component).WriteCaptions;
    1: TMyCaptionReader(Component).ReadCaptions;
  else
    inherited ExecuteVerb(Index)
  end;
end;

function TMyCaptionReaderEditor.GetVerb(Index: Integer): string;
begin
  case Index of
    0: Result := 'Write Captions...';
    1: Result := 'Read Captions...'
  else
    Result := inherited GetVerb(Index);
  end;
end;

function TMyCaptionReaderEditor.GetVerbCount: Integer;
begin
  Result := 2;
end;

constructor TMyCaptionReader.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FFileName := 'TheFile.txt';
end;

procedure TMyCaptionReader.Loaded;
begin
  inherited Loaded;
  ReadCaptions;
end;

procedure TMyCaptionReader.ReadCaptions;
var
  XStrings: TStringList;
  XComponent: TComponent;
  XPropInfo: PPropInfo;
  XName, XCaption: string;
  i, XPos: integer;
begin
  if not FileExists(FFileName) then
    exit;
  XStrings := TStringList.Create;
  try
    XStrings.LoadFromFile(FFileName);
    for i := 0 to XStrings.Count - 1 do
    begin
      XPos := pos('=', XStrings[i]);
      if XPos > -1 then
      begin
        XName := copy(XStrings[i], 0, XPos - 1);
        XCaption := copy(XStrings[i], XPos + 1, length(XStrings[i]) - 1);
        XComponent := Owner.FindComponent(XName);
        if Assigned(XComponent) then
        begin
          XPropInfo := GetPropInfo(XComponent, 'Caption');
          if Assigned(XPropInfo) then
            SetStrProp(XComponent, 'Caption', XCaption);
        end;
      end;
    end;
  finally
    XStrings.Free;
  end;
end;

procedure TMyCaptionReader.WriteCaptions;
var
  XStrings: TStringList;
  XComponent: TComponent;
  XPropInfo: PPropInfo;
  XCaption: string;
  i: integer;
begin
  XStrings := TStringList.Create;
  try
    if Assigned(Owner) then
    begin
      for i := 0 to Owner.ComponentCount - 1 do
      begin
        XComponent := Owner.Components[i];
        if Assigned(XComponent) then
        begin
          try
            XPropInfo := GetPropInfo(XComponent, 'Caption');
            if Assigned(XPropInfo) then
            begin
              XCaption := GetStrProp(XComponent, 'Caption');
              XStrings.Add(XComponent.Name + '=' + XCaption);
            end;
          except
          end;
        end;
      end;
    end;
    XStrings.SaveToFile(FFileName);
  finally
    XStrings.Free;
  end;
end;

Here's how the Register procedure could be:

procedure Register;
begin
  RegisterComponents('My Components', [TMyCaptionReader]);
  RegisterComponentEditor(TMyCaptionReader, TMyCaptionReaderEditor);
end;

Nincsenek megjegyzések:

Megjegyzés küldése