views:

830

answers:

7

Is is possible to create GUI for a Delphi application using an configuration pattern from an xml etc... file. Any frameworks exist for such an operation. It is easy with scripting like languages but can we simulate this behaviour in Delphi?

I need free library.

+3  A: 

Yes, it is possible. The pseudocode for this is something like this

var
  AParent:Tpanel;
  Edit:TControl;

for i := 0 to ConfigItems.Count - 1 do
begin
  if (ConfigItems[i].Type = 0) then Edit := TEdit.Create(AParent) as TControl
  else Edit := TAnotherEditOrAnotherControlType.Create(APanel) as TControl;
  //assume 20 pixels for each control, so thay will be placed one below another
  Edit.Top := i * 20; 
  //Left in this case can be fixed
  Edit.Left := 10;
  Edit.Parent := AParent;
 end;

This will create few TEdit or some other control (say, TAnotherEditOrAnotherControlType but if you declare Edit variable as a TControl, you can create any control you need) on TPanel declared as AParent. Of course instead of IF clause, you can declare big CASE statement, and create controls of appropriate type. Important lines are

  • add Parent as a parameter for dynamic control constructor (so that dynamic control can be freed automatically)
  • set dynamic controls Parent to our AParent panel - this line actually places control on parent panel.
smok1
A: 

You can find some examples here on Torry's using RTTI:

http://www.torry.net/quicksearchd.php?String=RTTI&Title=Yes

Jason T
+1  A: 
stukelly
+5  A: 

Take a look at XI Library or EControl.

ErvinS
+1, this XI library looks great.
mghie
XI seems to meet my requirements completely but one. It's not free. I should have mentioned that in the question at the first place.
+1  A: 

Glade also uses XML files to describe a GUI which is then created at runtime. Don't know whether it can be used with Delphi, though.

sleske
http://gtk2forpascal.sourceforge.net/ specifically libglade2.pas http://gtk2forpascal.cvs.sourceforge.net/viewvc/gtk2forpascal/gtk2/libglade/libglade2.pas?view=markup
Stobor
+1  A: 

Yes we can :) I have done this for a page designer that uses only Textboxes, Rules(lines) and Graphics but it should work for all registered controls.

[Off the cuff code approximation]

    var
      i, itemCount: Integer;
      AClassName: string;
      AnItemClass: TSomeBaseClass;
      AnItem: TSomeDrivedBaseClass
      ARect: TRect;
    begin
      // just so we have an initail size
      ARect.Left := 100;
      ARect.Top := 100;
      ARect.Bottom := 200;
      ARect.Right := 200;
      // Alist is a specialised TStringList
      for i  := 0 to itemCount - 1 do
      begin
        AClassName := Alist.ByKey['Class' + IntToStr(i)]; // locate class name 
        AnItemClass := TSomeBaseClass(GetClass(AClassName));  // ClassName must be registered
        AnItem := AnItemClass.Create(OwnerComponent, ARect, AParent);
        AnItem.LoadFromFile(IntToStr(i), AList);  // specialised loader that reads and sets all necessary properties
        AddItemToComponentList(AnItem);  // Add to form / frame / panel whatever
      end;
    end;

Of course you first need a "Form designer" that can save the design initially - the saving is just the reverse of the above...I'll leave that as an exercise for the Reader. wWth a little modification you could use Delphi and read the DFM file :)

Despatcher
+2  A: 

You can save and load dfm files from streams and files. You can save/load an entire form, or just a component and it's children.

Eg

As binary:

AStream.WriteComponent(AComponent);
MyComponent:=    Result:= AStream.ReadComponent(AComponent);

As text:

procedure WriteComponentAsText(AStream: TStream; AComponent: TComponent);
var
  BinStream:TMemoryStream;
begin
  BinStream := TMemoryStream.Create;
  try
    BinStream.WriteComponent(AComponent);
    BinStream.Seek(0, soFromBeginning);
    ObjectBinaryToText(BinStream, AStream);
  finally
    BinStream.Free
  end;
end;

function ReadComponentAsText(AStream: TStream; AComponent: TComponent): TComponent;
var
  BinStream:TMemoryStream;
begin
  BinStream := TMemoryStream.Create;
  try
    ObjectTextToBinary(AStream, BinStream);
    BinStream.Seek(0, soFromBeginning);
    Result:= BinStream.ReadComponent(AComponent);
  finally
    BinStream.Free
  end;
end;

You need to register any classes that you want to save or load with RegisterClass:

RegisterClass(TPanel);
SeanX