Jan 232018
 

With this post we are going to do a demo application to explain the use of the TMultiView component with the typical menu of mobile devices. In addition, the demo will have as a requirement that the forms shown in it will be embedded into a TPanel of the main form. To do this, once the form is created, we will change the parent of all its direct components by assigning their parent to the TPanel of the main form.

Another requirement of this demo, will be able to navigate backwards through the different forms that are created. For this we will define a “stack” LIFO (Last In First Out).

The TMultiView component

The TMultiView component allows us to create master-detail interfaces on any platform. In the master panel we can show any set of visual components (buttons, labels, lists, ….). These controls can be linked to a specific view of the detail panel.

Their most important properties are:

  • Mode: sets the presentation mode of the master panel. The different modes are the following:
    • Drawer: in this mode, the master panel can be hidden or overlap the detail panel.
    • Panel: the master panel is always shown anchored to right or left.
    • PlatformBehaviour: the application selects the presentation mode depending on the orientation and the type of device.
        

      Mobile Applications
      Device Type Device Orientation Master Pane Presentation
      Phone Landscape, Portrait Drawer (push/overlap)
      Tablet Landscape Docked panel
      Tablet Portrait Drawer (push/overlap)

       

      Desktop Applications
      OS Version Master Pane Presentation
      Windows 10 Navigation panel
      Windows 8 or earlier Docked panel
      OS X Docked panel

       

    • Popover: the master panel is shown in a drop-down menu.
    • NavigationPane:the master panel is shown with a minimum width defined in the CollapsedWidth property.
    • Custom: custom (for more info, read this link).
  • MasterButton: specifies which control will be used to show / hide the master panel. Essential for Drawer, Popover and NavigationPane modes.

The application

In this demo, we will use the TMultiView to create the typical application menu for mobile devices and the application forms will be displayed in a TPanel (named pContent). For this we will put in the main form the following components:

– A TToolBar with Top alignment, the header of the application.
Inside this, we will put 2 buttons, one aligned to the right (bBack button) and one to the left (bMultiview button). The first will do the “back” navigation or it will close the application if there are no screens to show again. To standardize your display according to platform, we will define your StyleLookup property to backtoolbutton. The second will show or hide the application menu. Like the bBack button, we will set the StyleLookup property to drawertoolbuttonbordered to standardize its display according to platform.

– A TMultiView (mvMenu), to which we will set the MasterButton property with the bMultiView button; and the Mode property to Drawer.
Inside the MultiView, we will add two buttons to show a form in each of them.

– A TPanel (pContent) to which we will set the Align property to Client.

To finish the visual work, we will create two forms with some control inside, the one we want, only to be able to check how they are changing. In the example, a button has been placed on each one, on the first form aligned to top and on the second to bottom.

Now that we have the whole design, let’s see the code.

First of all, will be define the “stack” of forms. For this we will use generics and we will declare the private variable FFrmList in the following way:

FFrmList: TObjectList<TCustomForm>;

This list will be created in the constructor of the class and we will destroy it in the destructor.

We will also define two methods for stacking and unstacking forms.

procedure PushForm(AForm: TCustomForm);
procedure PopForm;

The first one, PushForm, will receive the form to be stacked by parameter. In addition to stacking it, we will need to clean the area in case to showing a form. This will be done by returning the parent to the original form. Then, it will only be necessary to change the parent of the components of the form passed by parameter.

The second one, PopForm, will erase the current form, and in case there are stacked forms, it will show the last one.

And finally, we will define a method to create the forms.

procedure CreateForm(ClassForm: TFmxObjectClass);

This method will receive by parameter the class of the form to be created. In addition, to avoid duplicated names of objects, it will assign a name based on the system time (something to improve). Once the form is created, it will call to PushForm method.

To finish, we will have to program the OnClick events of the bBack button to unstack the forms, and of the menu buttons to create the forms, which will make a call to the CreateForm method.

Let’s see the code

procedure TForm2.bBackClick(Sender: TObject);
begin
  // if exist any visible form, do a pop
  if FFrmList.Count > 0 then
    PopForm
  else  // else, close the application
    Close;
end;

procedure TForm2.Button1Click(Sender: TObject);
begin
  // create a child form
  CreateForm(TForm3);
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
  // create a child form
  CreateForm(TForm4);
end;

constructor TForm2.Create(AOwner: TComponent);
begin
  inherited;

  FFrmList := TObjectList<TCustomForm>.Create;
end;

procedure TForm2.CreateForm(ClassForm: TFmxObjectClass);
var
  aForm: TCustomForm;
begin
  inherited;

  aForm := ClassForm.Create(Self) as TCustomForm;
  aForm.Name := aForm.Name + FormatDateTime('hhnnssmm', Now);
  PushForm(aForm);
  mvMenu.HideMaster;
end;

destructor TForm2.Destroy;
begin
  if Assigned(FFrmList) then
    FreeAndNil(FFrmList);

  inherited;
end;

procedure TForm2.PopForm;
var
  AForm: TCustomForm;
begin
  // if don't have stack forms, bye bye
  if FFrmList.Count = 0 then
    Exit;

  // we return parent references
  while pContent.ChildrenCount > 0 do
    pContent.Children[0].Parent := FFrmList.Items[FFrmList.Count - 1];

  // unstack last shown form
  FFrmList.Delete(FFrmList.Count - 1);

  // if any form is into the stack
  if FFrmList.Count > 0 then
  begin
    // get last form
    AForm := FFrmList.Items[FFrmList.Count - 1];

    // put new references to the principal container
    while AForm.ChildrenCount > 0 do
      AForm.Children[0].Parent := pContent;
  end;
end;

procedure TForm2.PushForm(AForm: TCustomForm);
begin
  // if exists an active form, we return the references
  if FFrmList.Count > 0 then
  begin
    while pContent.ChildrenCount > 0 do
      pContent.Children[0].Parent := FFrmList.Items[FFrmList.Count - 1];
  end;

  // adds new form to the stack
  FFrmList.Add(AForm);

  // we assign new references to the principal container
  while AForm.ChildrenCount > 0 do
    AForm.Children[0].Parent := pContent;
end;

Like usually, here you have the code of the demo.

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

This site uses Akismet to reduce spam. Learn how your comment data is processed.