Continuation of the cycle of articles “Production”

The minimalistic main menu-based form selection interface of a table view has one significant drawback: every time you need to select a form, you have to travel through the menu items. To make it easier to switch between windows that are already open, let’s add a navigator to the application.

Form navigator or window navigator is a mechanism for switching between previously opened windows. 

The navigator looks like multipage tab buttons or tabs. An ideal candidate for the role of a navigator is the class TTabControl – a list of buttons (tabs). Unfortunately, in My Visual Database for this class, support for handling the onChange event, which is based on the window switching functionality, is not implemented, so we will make the navigator for the “Production” program based on class TdbPageControl. It differs from TTabControl in that, in addition to buttons, it contains special containers – tabs on which you can place user interface elements. In our case, this is not necessary, since the selected form is always displayed on the same element of the main form, and switching between forms occurs through controlling the visibility of forms and its location relative to other forms – calling the BrigToFront method brings the selected form to the front and it hides other forms already on the same panel.

There is already a Form_ShowOnWinControl() procedure for displaying a form on another component. But to interact with the navigator, it is better to make a separate procedure, since not all forms need a navigator (for example, forms displayed on the edit form). Since the navigator is a structural unit of the main form, it is logical to name the new procedure Form_ShowOnMainForm().

const
  // enable form navigator
  FORM_NAVIGATOR_ENABLED = True;
  // special controls
  FORM_WORK_PANEL = 'panWork';
  FORM_NAVIGATOR = 'pgcFormNavigator';
  FORM_CLOSE_BUTTON = 'btnClose';
  FORM_CLOSE_BUTTON_CAPTION = chr($D7);
  FORM_CLOSE_BUTTON_HINT = 'Close Window';

procedure Form_ShowOnMainForm(AForm: TForm;);
// display on the main form, the navigator is enabled
var
  tmpPanel: TdbPanel;
  tmpPC:TdbPageControl;
  tmpTabSheet: TdbTabSheet;
  tmpName:string;
  tmpButton: TdbButton;
begin
  tmpName := DeleteClassName(AForm.Name);
  FindC(MainForm,FORM_WORK_PANEL,tmpPanel); // working panel of the main form
  Form_ShowOnWinControl( AForm, tmpPanel );
  // navigator mechanics
  if FORM_NAVIGATOR_ENABLED then
  begin
    FindC(MainForm,FORM_NAVIGATOR,tmpPC,False);
    // if the navigation bar is not found, then create it
    if tmpPC = nil then
    begin
      tmpPC := TdbPageControl.Create( MainForm );
      AssignEvents(tmpPC);
      with tmpPC do
      begin
        Parent := tmpPanel.Parent;
        Name := FORM_NAVIGATOR;
        Font.Size := 11;
        Height := 34; // minimum height for selected font size
        TabPosition := tpBottom;
        Align := alBottom;
        dbonChange := 'Form_Navigator_OnChange';
      end;
      // adjust the alignment of the working panel
      tmpPanel.Anchors := 0;
      tmpPanel.Align := alClient;
    end;
    // find tab and switch
    FindC(MainForm,T_TAB_SHEET+tmpName,tmpTabSheet,False);
    if tmpTabSheet = nil then
    begin // if there is no tab, create it
      tmpTabSheet := TdbTabSheet.Create( MainForm );
      tmpTabSheet.Name := T_TAB_SHEET+tmpName;
      tmpTabSheet.PageControl := tmpPC;
      tmpTabSheet.Caption := AForm.Caption;
    end;
    tmpPC.ActivePage := tmpTabSheet;
    // form close button
    FindC(AForm,FORM_CLOSE_BUTTON,tmpButton,False);
    if tmpButton = nil then
    begin // if there is no button, then create it
      tmpButton := TdbButton.Create( AForm );
      AssignEvents(tmpButton);
      with tmpButton do
      begin
        Name := FORM_CLOSE_BUTTON;
        Parent := AForm;
        Width := 18;
        Height := 18;
        top := 0;
        Left := AForm.ClientWidth - Width - 1;
        Anchors := akTop + akRight;
        Caption := FORM_CLOSE_BUTTON_CAPTION;
        Font.Size := 11;
        Font.Style := fsBold;
        Hint := FORM_CLOSE_BUTTON_HINT;
        ShowHint := True;
        OnClick := @Form_Navigator_btnClose_OnClick;
      end;
    end;
    tmpButton.Visible := True;
    tmpButton.BringToFront;
  end;
end;
Code language: Delphi (delphi)

This procedure not only displays the form, but also activates the navigator mechanism, creating the necessary user interface elements. To switch forms using the navigator buttons, the Form_Navigator_OnChange() procedure is used.

procedure Form_Navigator_OnChange(Sender: TObject);
// toggle the visibility of forms using the form navigator
var
   tmpPC:TdbPageControl;
   tmpTabSheet: TdbTabSheet;
   tmpForm:TAForm;
begin
   tmpPC := TdbPageControl( Sender ); // navigator
   tmpTabSheet := TdbTabSheet(tmpPC.ActivePage); // active tab
   tmpForm := App_GetFormByName( T_FORM + DeleteClassName(tmpTabSheet.Name) ); // associated form
   Form_ShowOnMainForm(tmpForm); // show form
end;
Code language: Delphi (delphi)

Another optional procedure is Form_Navigator_btnClose_OnClick(), which closes the form and removes the window control button from the navigator bar.

procedure Form_Navigator_btnClose_OnClick(Sender: TObject; var Cancel: boolean);
// close form and navigator tab
var
   tmpForm:TAForm;
   tmpTabSheet: TdbTabSheet;
begin
   CForm(Sender,tmpForm);
   tmpForm.Hide;
   FindC( MainForm ,T_TAB_SHEET+DeleteClassName(tmpForm.Name),tmpTabSheet,False);
   if tmpTabSheet <> nil then
     tmpTabSheet.Free;
end;
Code language: PHP (php)

To be continued.

Leave a Reply

Your email address will not be published. Required fields are marked *