ene 232018
 

Con la entrada de hoy vamos a crear una aplicación demo para explicar el uso del componente TMultiView y crear el típico menú de dispositivos móviles. Además, la demo tendrá como requisito que los formularios mostrados en ella sean embebidos dentro de un TPanel del formulario principal. Para ello, una vez creado el formulario, vamos a cambiar el parent de todos sus componentes directos asignándoles como parent el TPanel del formulario principal.

Otro requisito de la aplicación, será poder navegar hacia atrás por los diferentos formularios que se vayan creando. Para ellos definiremos una “pila” LIFO (Last In First Out).

El componente TMultiView

El componente TMultiView nos permite crear interfaces master-detail en cualquier plataforma. En el panel master podemos visualizar cualquier conjunto de componentes visuales (botones, etiquetas, listas,….). Estos controles se pueden lincar a una vista concreta del panel detalle.

Sus propiedades principales son:

  • Mode: establece el modo de presentación del panel maestro. Los diferentes modos son los siguiente:
    • Drawer: en este modo, el panel maestro puede estar oculto o superponerse al panel detalle.
    • Panel: el panel maestro siempre se muestra anclado a derecha o izquierda.
    • PlatformBehaviour: la aplicación selecciona el modo de presentación dependiendo de la orientación y del tipo de dispositivo.
        

      Aplicaciones móviles
      Tipo de dispositivo Tipo de Orientación Presentación panel maestro
      Phone Landscape, Portrait Drawer (push/overlap)
      Tablet Landscape Docked panel
      Tablet Portrait Drawer (push/overlap)

       

      Aplicaciones de escritorio
      Versión del S.O. Presentación panel maestro
      Windows 10 Navigation panel
      Windows 8 or earlier Docked panel
      OS X Docked panel

       

    • Popover: el panel maestro se muestra en un menú desplegable.
    • NavigationPane: el panel maestro se muestra con una anchura mínima definida en la propiedad CollapsedWidth.
    • Custom: personalizado (para más info, leer este enlace).
  • MasterButton: especifica qué control servirá para mostrar/ocultar el panel maestro. Imprescindible para los modos Drawer, Popover y NavigationPane.

La aplicación

En el ejemplo de hoy, usaremos el TMultiView para crear el menú de aplicación típico de dispositivos móbiles y los formularios de la aplicación se visualizarán en un TPanel (de nombre pContent). Para ello pondremos en el formulario principal los siguientes componentes:

– Un TToolBar con alineación Top que nos hará de cabecera.
Dentro de éste, pondremos 2 botones, uno alineado a derecha (botón bBack) y otro a izquierda (botón bMultiview). El primero nos hará la navegación inversa o cerrará la aplicación si no quedan pantallas por volver a mostrar. Para estandarizarlo su visualización según plataforma, definiremos su propiedad StyleLookup a backtoolbutton. El segundo será el encargado de mostrar o ocultar el menú de la aplicación. Al igual que el bBack, estableceremos la propiedad StyleLookup a drawertoolbuttonbordered para estandarizar su visualización según plataforma.

– Un TMultiView (mvMenu), al que estableceremos la propiedad MasterButton con el botón bMultiView; y la propiedad Mode a Drawer.
Dentro del MultiView, añadiremos dos botones para mostrar un formulario en cada uno de ellos.

– Un TPanel (pContent) al que estableceremos la propiedad Align a Client.

Para terminar la parte visual, crearemos un par de formularios con algún control dentro, el que queramos, sólo será para poder comprobar como van cambiando. En el ejemplo se ha puesto un botón en cada uno, en el primer formulario alineado arriba y en el segundo abajo.

Ahora que ya tenemos todo el diseño, vamos a ver el código.

Lo primero será definir la “pila” de formularios. Para ello usaremos genéricos y declararemos la variable privada FFrmList de la siguiente manera:

FFrmList: TObjectList<TCustomForm>;

Esta lista la crearemos en el constructor de la clase y la destruiremos en el destructor.

También definiremos dos métodos para apilar y desapilar formularios.

procedure PushForm(AForm: TCustomForm);
procedure PopForm;

El primero, PushForm, recibirá por parámetro el formulario a apilar. Además de apilarlo, necesitaremos limpiar el área en el caso de que ya se estubiera visualizando un formulario. Ésto lo haremos devolviendo el parent a su formulario original. Luego, sólo quedará cambiar el parent de los componentes del formulario pasado por parámetro.

El segundo, PopForm, borrará el formulario actual, y en caso de que haya formularios apilados, mostrará el último.

Y para terminar, definiremos un método para crear los formularios.

procedure CreateForm(ClassForm: TFmxObjectClass);

Este método recibirá por parámetro la clase del formulario a crear. Además, para evitar nombres de objetos repetidos, le asignará un nombre basado en la hora del sistema (algo a mejorar). Una vez creado el formulario, hará una llamada a PushForm.

Para terminar, tendremos que programar los eventos OnClick del botón bBack para desapilar los formularios, y de los botones de menú para crear los formularios, los cuales harán una llamada al método CreateForm.

Veamos cómo queda el código

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;

Como siempre, aquí tenéis los fuentes de la 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)