How to split TPageControl tabs into separate files in Delphi?

I have a VCL form with five tabs TPageControl on it. Each TTabSheet content TTabSheet quite unrelated and has many separate controls and processing logic ... so I want to break it down to make it easier to handle the code for "just this tab." Having a string like

 //-------------------------- begin rules tab methods ------------------- 

just doesn't cut anymore. In fact, I think I will like each tab in a separate file.

I am currently considering creating a VCL frame for each TTabPage. If I did this, I would either have to load all frames into the TPageControl in the constructor, or when the tab is displayed.

Is this a good approach? Would it be better to do the whole TForm for each tab? Should I continue to migrate tabs to TPageControl or should I change to TTabControl if the content is loading dynamically? If this is a good approach, is it better to load all tabs at startup or every time a tab is displayed? (maybe pros / cons if it's not completely obvious, which is better in most cases).

+7
delphi vcl tpagecontrol
source share
2 answers

You can use either frames or forms.

  • With frames, you need to add TabControl as the parent for each frame.
  • Using forms you have to dock each form in PageControl (the signature of the form will be the automatic signature of TabControl).

 procedure TMyForm.AddPage( AFormClass : TFormClass ); var LForm : TForm; begin LForm := AFormClass.Create( Self ); LForm.ManualDock( PageControl1, nil, alClient ); LForm.Show; end; 

Example

Create a basic setup form

 unit UI_Form_SettingBase; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs; type TUISettingBase_Form = class( TForm ) private protected procedure DoSaveData; virtual; public function CanSaveData : Boolean; virtual; procedure SaveData; end; TUISettingBase_FormClass = class of TUISettingBase_Form; var UISettingBase_Form : TUISettingBase_Form; implementation {$R *.dfm} { TUISettingBase_Form } function TUISettingBase_Form.CanSaveData : Boolean; begin Result := True; end; procedure TUISettingBase_Form.DoSaveData; begin end; procedure TUISettingBase_Form.SaveData; begin if CanSaveData then DoSaveData; end; end. 

Derive all configuration forms from this form and override DoSaveData and, if necessary, CanSaveData methods

General settings (with simple CheckBox)

 unit UI_Form_SettingCommon; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, UI_Form_SettingBase, Vcl.StdCtrls; type TUISettingCommon_Form = class(TUISettingBase_Form) CheckBox1: TCheckBox; private protected procedure DoSaveData; override; public end; var UISettingCommon_Form: TUISettingCommon_Form; implementation {$R *.dfm} procedure TUISettingCommon_Form.DoSaveData; begin inherited; // code to save the data end; end. 

Connection options (using a simple Edit control)

 unit UI_Form_SettingConnection; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, UI_Form_SettingBase, Vcl.StdCtrls; type TUISettingConnection_Form = class( TUISettingBase_Form ) Edit1 : TEdit; private protected procedure DoSaveData; override; public end; var UISettingConnection_Form : TUISettingConnection_Form; implementation {$R *.dfm} { TUISettingConnection_Form } procedure TUISettingConnection_Form.DoSaveData; begin inherited; // code to save the data end; end. 

Addition of parts: the real form of settings

The main configuration form is also derived from the SettingBase parameter.

 unit UI_Form_Settings; interface uses System.Generics.Collections, Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, UI_Form_SettingBase, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls; type TUISettings_Form = class( TUISettingBase_Form ) PageControl1 : TPageControl; Panel1 : TPanel; Save_Button : TButton; private FForms : TList<TUISettingBase_Form>; procedure AddSettingPage( ASettingFormClass : TUISettingBase_FormClass ); protected procedure DoSaveData; override; public function CanSaveData : Boolean; override; procedure AfterConstruction; override; procedure BeforeDestruction; override; end; var UISettings_Form : TUISettings_Form; implementation {$R *.dfm} uses UI_Form_SettingCommon, UI_Form_SettingConnection; { TUISettings_Form } procedure TUISettings_Form.AddSettingPage( ASettingFormClass : TUISettingBase_FormClass ); var LForm : TUISettingBase_Form; begin LForm := ASettingFormClass.Create( Self ); try LForm.ManualDock( PageControl1, nil, alClient ); LForm.Show; FForms.Add( LForm ); LForm := nil; finally LForm.Free; end; end; procedure TUISettings_Form.AfterConstruction; begin inherited; FForms := TList<TUISettingBase_Form>.Create; // add all the setting forms AddSettingPage( TUISettingCommon_Form ); AddSettingPage( TUISettingConnection_Form ); end; procedure TUISettings_Form.BeforeDestruction; begin inherited; FForms.Free; end; function TUISettings_Form.CanSaveData : Boolean; var LForm : TUISettingBase_Form; begin // iterate all setting forms if they can save the data Result := True; for LForm in FForms do Result := Result and LForm.CanSaveData; end; procedure TUISettings_Form.DoSaveData; var LForm : TUISettingBase_Form; begin inherited; // iterate all setting forms and save the data for LForm in FForms do LForm.SaveData; end; end. 
+7
source share

One thing in particular that I would like to do (the focus of this question) is to somehow break up a TPageControl containing five TTabSheets. Each tab sheet is a pretty cohesive part of the user interface (and the corresponding processing logic), so it would be nice to split each tab into separate files.

You can use TFrame for this. Give each page its own frame, which you can implement and create in your separate files with your own DFMs.

For each broken tab, I would like to start by adding new VCL forms? or vcl frames?

Frames. Do not use inline forms, they do not work very well. Personnel were developed for this purpose.

Should I leave TPageControl or change it to TTabControl if the contents of each tab are loaded from the panel?

After creating a new frame and developing it as necessary, you can either:

  • place the frame on the component palette (right-click on the frame in the designer and select "Add to Palette"), and then you can drop it onto the desired TTabSheet during development. Set Frame Align to alClient if you want it to fill in the entire TTabSheet .

  • instantiate the Frame object in your code at runtime, and then set its Parent property to the desired TTabSheet .

+7
source share

All Articles