Move a TabSheet between PageControls

3.1k views Asked by At

I'm using Delphi 7 currently.

I have a main Form, it has a PageControl with 5 tabs on it. I'm looking for a way to 'Detach' these tabsheets from the pagecontrol and move them individually to a new form, that is created runtime. The moved sheet needs to retain all it's components (buttons, labels, etc) and function almost the same as it was still in it's place in the pagecontrol.

Basically, the idea is that if a user wants to view 2 (or more) pages simultaneously, then he/she can drag that sheet out of the form's area and it creates a new window for it. When the user is done, the extra form is closed with the X button, the sheet goes back to it's original place in the pagecontrol.

And just for the extra challenge: Is it possible to make this solution into a separate unit so it could be called to 'detach' any controls at runtime? (buttons, edits, listboxes, images, etc.)?

Thanks!
Thomas

2

There are 2 answers

0
bummi On BEST ANSWER

The approach shown here differs from your from your starting position, but might come near to your demands.
The idea is to use an empty PageControl on which the tabs are paced at runtime.
Each Tab would be an own form based on an ancestor, here TTemplate which will provide two properties for then Dockcontrol and the Pageindex.
ManualDock(PageControl) can be used to add it to and ManualDock(nil) to remove it from the Pagecontrol.
CloseQuery is used here to redock it and to restore the PageIndex.
In this example a DoubleClick will undock the form.

example for filling the Pagecontrol:

procedure TDemoForm.FormCreate(Sender: TObject);
var
 i:Integer;
begin
  for I := 0 to 9 do
      begin
        With TTemplate.Create(self) do
          begin
            Color := Random(255*255);
            MyDockControl := PageControl1;
            DockTabIndex  := i;
            Ctl3d := false;
            Caption := Format('Tab %d',[i]);
            Show;
          end;
      end;
end;

and a draft for the template:

type
  TTemplate = class(TForm)
    Button1: TButton;
    RadioGroup1: TRadioGroup;
    procedure FormDblClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  private
    FMyDockControl: TWinControl;
    FDockTabIndex: Integer;
    procedure SetMyDockControl(const Value: TWinControl);
    procedure Redock;
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    Property MyDockControl:TWinControl read FMyDockControl Write SetMyDockControl;
    Property DockTabIndex:Integer read FDockTabIndex write FDockTabIndex;
  end;

var
  Template: TTemplate;

implementation

{$R *.dfm}

procedure TTemplate.Redock;
begin
  if Assigned(MyDockControl) then ManualDock(MyDockControl);
  if MyDockControl is TPageControl then
     TPageControl(MyDockControl).Pages[TPageControl(MyDockControl).ActivePageIndex].PageIndex := DockTabIndex;
end;

procedure TTemplate.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
   CanClose := not Assigned(MyDockControl);
   Redock;
end;

enter image description here

2
NGLN On
  • Move all controls to a separate Frame.
  • Set Frame.DragKind to dkDock.
  • Set Frame.DragMode to dmAutomatic.
  • Set Form.PageControl.DockSite to True.
  • Et voilá.

See the sample in C:\Program Files\Borland\Demos\Docking for inspiration on how to customize this further.