Link to home
Start Free TrialLog in
Avatar of essbb
essbb

asked on

Duplicating controls at run time.

I need to create a duplicate copy of a control at run time. The main control I need to duplicate is a TabControl and allthe components that it contains and put it in a dynamically created form. All the duplicated controls need to have the same values of the original (I cannot just create new ones) Also I cannot just move the original control (by adjusting parent) to new form because both forms may be on screen at the same time.I do not want to use the clipboard to avoid corrupting clip board info from this & other apps.Can anybody help?
Avatar of essbb
essbb

ASKER

By the way, I am using delphi 2.01
ASKER CERTIFIED SOLUTION
Avatar of andrewjb
andrewjb
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of essbb

ASKER

The first method will not work. If I create a new instance of form A all the components will contain the initial values / states for that form. I need to duplicate the current values.

I also need to have the events linked up properly so the second option will not work.

I do like the simplicity of the first approach and It may make a sutiutable 'work around' in that I could create a new instance and then add code to set the properties and states to match the parent.

I Would however much prefer to duplicate the object if possible as this seems much more eligent and will ensure that all the existing controls and any that I introduce in the future are duplicated correctly.

Do you have any more suggestions?

Sorry, I didn't quite understand.

You could stream out the current set of components, then create a version of form A telling it to use the stream that you've just created. That should also set up the event handlers correctly. I'll have to look up how to do that, and see if I can get it working. Give me a few moments.........
Avatar of essbb

ASKER

Do you have a solution for me or can I Reject your answer and see if someone else knows?


Here's something to work on. I'll have another look if I get a minute or two! This attempts to copy a panel and everything on it, at run time. Basically I stream stuff out to a tMemoryStream, then try to load it back in. It doesn't quite work yet!

The code assumes you've got a panel called Panel1 on the form TForm1.





procedure TForm1.Button2Click(Sender: TObject);
var
  lList : TList;
  lListIndex : integer;
  lControlIndex : integer;
  lStream : tMemoryStream;
  lWriter : TWriter;
  lReader : TReader;
  lIndex : integer;
  lControl : TControl;
  lNewForm : TForm1;
  lNew : TPanel;
begin
  lList := TList.Create;

  { Make a list of all the controls on the panel we want to copy }
  lList.Add( Panel1 );
  lListIndex := 0;
  while ( lListIndex < lList.Count ) do
  begin
    lControl := TControl(lList[lListIndex] );
    if ( lControl is tWinControl ) then
    begin
      for lControlIndex := 0 to tWinControl(lControl).ControlCount - 1 do
      begin
        lList.Add( tWinControl(lControl).Controls[lControlIndex] );
      end;
    end;
    Inc( lListIndex );
  end;

  lStream := tMemoryStream.Create;
  lWriter := tWriter.Create( lStream , 1 );
  lReader := tReader.Create( lStream , 1 );

  lNewForm := TForm1.Create( Self );
  lNew := TPanel.Create( lNewForm );
  lNewForm.Panel1.Free;

  { Write the current panel out }
  for lIndex := 1 to lList.Count - 1 do
  begin
    lControl := TControl(lList[lIndex]);
    lWriter.WriteSignature;
    lWriter.WriteComponent( lControl );
  end;
  lWriter.WriteListEnd;
  lWriter.WriteBoolean( True );
  lWriter.Free;

  { Read the new panel in }
  lStream.Seek( 0 , 0 );
  lReader.ReadComponents( lNewForm , lNew , DummyProc );

  lNew.Parent := Self;
  lNew.SetBounds( 100 , 100 , 200 , 200 );

  { Free up }
{  lList.Free;
  lStream.Free;
  lWriter.Free;
  lReader.Free;}

end;

Create a TMemoryStream, a TReader and a TWriter object.
Connect the TReader and the TWriter to the stream.
Use the source control's WriteState method to save the contents
of the control to the stream.
Create the target control if doesn't exist.
Use the target control's ReadState method.

I didn't look into the details, but it have to work.

Maybe you have to clear all child controls from target.
Maybe you have to reset the Stream's position before writing and
reading.