Sie sind auf Seite 1von 10

Delphi paso a paso (VII): Aplicaciones MDI

Por Vladimir Algara

En este artculo se van a enumerar los pasos que deben seguirse para proyectar una sencilla aplicacin MDI. Bien es cierto que han sido muchas las veces en las que se ha explicaco el concepto de aplicacin MDI en contraposicin al de SDI, pero me parece obligado hacer una pequea resea de la caracterstica que distingue a una y a otra. Las siglas MDI (Multiple Documents Interface, o lo que es lo mismo Interfaz de Documentos Mltiples) identifican a las aplicaciones en las que se dispone de una ventana principal y todo un conjunto de hijas que dependen de ella; este conjunto puede ser abierto sin necesidad de ir cerrando progresivamente las ventanas ya existentes. En contraposicin a las citadas siglas aparecen las SDI (Single Document Interface, o lo que es lo mismo Interfaz de Documento Sencillo) en el que aparece la presentacin de una nica ventana hija por vez, lo cual quiere decir que para obtener una segunda ventana hija, forzosamente, hay que cerrar la actual. Para ilustrar el ejemplo se va a realizar una aplicacin en la que se permita mostrar un nmero indefinido de ventanas, donde se podr teclear una serie de nmeros, con los cuales operar aritmticamente; es decir, sin pretensin de otra cosa que ilustrar, se crear una rudimentaria calculadora (y la palabra rudimentaria alcanzar con este ejemplo un significado indiscutible) que ser llamada cuantas veces se quiera desde una ventana padre, encargada de distribuir la lgica del funcionamiento a lo largo de la vida de la aplicacin.

Ventana marco (o ventana padre)


Como ya se ha dicho, una aplicacin MDI dispone de una ventana padre que se encarga de la gestin general del programa. Desde ella, y habitualmente por medio de los tems de un men, se llama cuantas veces sea necesario a su o sus ventanas hijas, las cuales tendrn un comportamiento propio como si de programas aislados e independientes se tratara. Como primer paso se crear la ventana marco de aplicacin, a la cual dotaremos con las caractersticas de las ventanas MDI. Esta operacin, como ya estamos acostumbrados a hacer, se realizar modificando la pertinente propiedad del inspector de objetos asociado a la ventana. Por tanto, una vez dentro de Delphi, partamos de un formulario (Form) vaco y cambiemos las propiedades especificadas en la tabla 1.

Propiedad Valor Original Nuevo Valor Caption Form1 Ventana MDI FormStyle fsNormal fsMDIForm Name Form1 VentanaMDI WindowState wsNormal wsMaximized Tabla 1. Valores originales y nuevos para la ventana marco

La propiedad Caption se encarga de cambiar el ttulo de la ventana, FormStyle hace que la ventana no sea una de las creadas por defecto, sino que se comportar como despachadora de ventanas, ser aplicacin MDI, Name hace que cualquier referencia a la ventana padre sea a travs del nombre asignado, ya que siempre ser ms representativo que el genrico Form1, Form2, etc. (siempre que se haga referencia a la ventana padre, ya sea por el cdigo tecleado por nosotros como por el generado automticamente por Delphi, se realizar por medio de este identificativo, en nuestro caso VentanaMDI); por ltimo, se ha modificado la propiedad

1
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

WindowState para que nada ms arrancar la aplicacin la ventana principal aparezca maximizada a la totalidad de la pantalla).
Ms adelante, cuando dispongamos del men general de la aplicacin, la propiedad Menu habr de ser actualizada con el diseado para la ocasin.

Men principal
Recordemos, someramente, cmo disear nuestros mens; aunque para ms detalles se remite al lector a los manuales de usuario o al artculo sobre mens en Delphi publicado en el nmero 17 de Algoritmo.

Lo elementos que nos encontraremos, tanto para la ventana marco como para las hijas, se describen y enumeran ms abajo. 1.- Lnea donde se escribir cada opcin principal del men. En esta lnea se especifican las distintas opciones principales que componen el cuerpo central del men. 2.- Lneas donde se escribirn cada una de las opciones secundarias. En esta lnea se especifican las distintas subopciones de las opciones principales. 3.- Lneas donde se escribirn cada una de las subopcines. En esta lnea se especifican las distintas subopciones anidadas. En cualquiera de los tres casos anteriores (o cualquier otro nivel de anidacin de subopciones), si quisiramos activar un Hot-Key para cada opcin, bastara con anteponer a la letra en cuestin el smbolo &: &Salir creara como Hot-Key la letra S Para crear subopciones a una opcin, lo nico que tendremos que hacer es pulsar el botn izquierdo del ratn sobre la opcin secundaria seleccionada, eligiendo Create Submenu (o pulsando [Ctrl-flecha derecha]) en el men local asociado. 4.- Separadores entre subopciones. Para aadir este elemento visual basta con escribir un guin y pasar a la siguiente lnea. Aparecer una lnea separadora. 5.- Abreviatura de teclado para acceso rpido a opciones. Los mens, y ms concretamente los tems que componen un men, slo tienen un evento; aqul que sucede cuando se elige alguna de las opciones. Por eso la carpeta Events slo dispone del evento OnClick(). Si queremos especificar un evento concreto, basta con escribir en el combo asociado a OnClick() el nombre del procedimiento que queremos ejecutar cuando hagamos Clic, y pulsar [Intro]. Esto har que el nombre de dicho evento se registre en el bloque type, y que se escriba, automticamente, las lneas esenciales de ese mtodo. Por ejemplo si escribimos SalirClick y asociamos una accin obtendremos el cdigo del fuente 1.

2
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

// --- Fuente 1 -------------------------------------------------------procedure TVentanaMDI.SalirClick(Sender: TObject); begin Close end;

Para confeccionar el men de la ventana principal se han especificado los tems, las teclas aceleradoras y los eventos asociados de la tabla 2.

Items Ejecutar

Caption Acelerador Ejecutar Calculadora C&alculadora Separador Salir Salir Ventanas Ventanas Cascada Cascada Mosaico Mosaico Iconizar Iconizar Tabla 2: Men de la ventana principal

Evento Ctrl-A Ctrl-Z Calcular SalidaClick Cascada Mosaico Iconizar

El aspecto de la ventana principal, tal y como se ha diseado, que no maximizada, debe ser similar al que se muestra en la figura 1.

Figura 1: Aspecto de la ventana principal.

Eventos del men


El evento de Salir de la aplicacin ya se ha comentado, pasemos a comentar los que restan, que son dos. Uno, el de visualizacin de las ventanas instanciadas y que es similar para Cascada, Mosaico e Iconizar. Lo nico que en ellos se hace es llamar al procedimiento que realiza la accin adecuada, y que respectivamente son Cascade, Tile y ArrangeIcons, tal y como se ve en el fuente 2.

3
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

// --- Fuente 2 -------------------------------------------------------procedure TVentanaMDI.Cascada(Sender: TObject); begin Cascade end; procedure TVentanaMDI.Mosaico(Sender: TObject); begin Tile end; procedure TVentanaMDI.Iconizar(Sender: TObject); begin ArrangeIcons end;

El procedimiento en que nos detendremos algo ms ser sobre el encargado de mostrar la calculadora una vez invocada desde el men principal. Se podra ensayar una sencilla llamada al procedimiento Show genrico, pero esta operacin deja sin efecto las especificaciones de la ventana dadas en el inspector de objetos (por ejemplo posicin y tamao), siendo fijadas stas por la ventana padre. Si lo que queremos es que la ventana se muestre segn los parmetros dados al disearla, la forma de proceder ser la que se ofrece en el fuente 3

// --- Fuente 3 -------------------------------------------------------procedure TVentanaMDI.Calcular(Sender: TObject); var CalcForm: TVentanaCalculadora; begin CalcForm := TVentanaCalculadora.Create(Self) end;

Se habilita una variable para dar claridad al cdigo y por si queremos hacerla ms genrica. A continuacin, en vez de ejecutar un Show, creamos un objeto mediante el procedimiento genrico Create, al cual le pasamos como parmetro la ventana marco (Self), para que se sepa quin es el propietario de la ventana recin creada (el de la calculadora). Una vez hecho esto, la ventana aparecer con las caractersticas dadas en el inspector de objetos, y no como la ventana marco fija. Para finalizar, y con las miras puestas en la conservacin de lo que vamos creando, salvaremos nuestro trabajo, pero teniendo la precaucin de darle un nombre distinto al que Delphi le da por defecto. Accediendo a Save as.. del men File le podemos llamar Padre.

Ventana hija
Son las ventanas llamadas desde la ventana principal. Como caracterstica esencial que las define nos encontramos con que la propiedad FormStyle est especificada como fsMDIChild. Esto provoca que su comportamiento est, en todo momento, supeditado a las vicisitudes de la ventana padre.

4
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

Como primer paso, y como ocurri anteriormente, se crear la ventana hija (Child), a la cual dotaremos con las caractersticas de las ventanas MDIChild. Esta operacin se realiza, como antes, modificando la pertinente propiedad del inspector de objetos asociado a la nueva ventana. Las propiedades fijadas se especifican en la tabla 3.

Propiedad Valor Original Nuevo Valor Caption Form1 "Calculadora" FormStyle fsNormal fsMDIChild Name Form1 VentanaCalculadora Tabla 3: Valores originales y nuevos para la ventana hija

Nuevamente, la propiedad Caption se encarga de cambiar el ttulo de la ventana, FormStyle hace que la ventana no sea una de las creadas por defecto, sino que se comportar como hija de la ventana marco Ms adelante, cuando dispongamos del men de la "calculadora", la propiedad Menu habr de ser actualizada.

Men de la calculadora
Para confeccionar el men de la ventana principal se han especificado los tems, las teclas aceleradoras y los eventos asociados de la tabla 4.

Items Nmeros

Caption Acelerador Evento Nmeros 0..9 &0..&9 Operaciones Operaciones Suma Suma Resta Resta Multiplicacin Multiplicacin Divisin Division Igual a Igual a Borrar Borrar Tabla 4: Men de la ventana que alberga la calculadora

El0, El1,.., El9 PbOperar PbOperar PbOperar PbOperar PbIgualar Borrar

El aspecto de la ventana hija debe ser similar al que se muestra en la figura 2.

5
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

Figura 2: Aspecto de la ventana hija

Veamos cmo se comportan los diversos procedimientos y comentemos sus caractersticas ms destacables.

// --- Fuente 4 -------------------------------------------------------procedure TVentanaCalculadora.El0(Sender: TObject); begin Agregar( 0 ) end; procedure TVentanaCalculadora.El1(Sender: TObject); begin Agregar( 1 ) end; . . . . . . procedure TVentanaCalculadora.El9(Sender: TObject); begin Agregar( 9 ) end;

En el fuente 4 se ve cmo en cada uno de los procedimientos asociados a los botones (y a los tems del men) que simbolizan los nmeros de la calculadora (El0, El1,...,El9), se llama a un procedimiento auxiliar que recibe el nmero a aadir en el control de edicin. Una de las muchas mejoras que puede sufrir la "calculadora" es la de impedir teclear un cero si no se ha introducido previamente otro nmero, o permitir teclear nmeros decimales, etc., etc. En cualquier caso el procedimiento Agregar se ve en el fuente 5.

// --- Fuente 5 -------------------------------------------------------var VentanaCalculadora: TVentanaCalculadora; Ch: string[1]; nValor: integer; . . .

6
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

procedure TVentanaCalculadora.Agregar( nValor: byte ); begin Resul.Text := Resul.Text + IntToStr(nValor) end; . . . initialization Ch := '+'; nValor := 0;

El procedimiento podra no haber pertenecido a la clase TVentanaCalculadora, pero en tal caso no se podra haber accedido a ninguno de los controles de la ventana, y en este procedimiento se altera el contenido del control de edicin. Por tanto, como s es necesario que pertenezca a la clase deberemos informar de ello en la seccin type de su definicin (ver fuente 6). La variables nValor y Ch se han declarado como pblicas del mdulo, y van a servir para almacenar el primer operando y el operador a usar (la inicializacin de ambas variables se hace en la seccin Initialization).

// --- Fuente 6 -------------------------------------------------------type TVentanaCalculadora = class(TForm) MainMenu1: TMainMenu; Nmeros1: TMenuItem; . . . . . . procedure El0(Sender: TObject); procedure El1(Sender: TObject); . . . . . . procedure El9(Sender: TObject); procedure Agregar( nValor: byte ); . . . . . .

Como se ve en la tabla 4, Suma, Resta, Multiplicacin y Divisin tienen un procedimiento comn, el que se ha llamado PBOperar, y dado que es comn habr que distinguir en su interior si se ha llamado por uno o por otro botn (Sender). Si a esto le sumamos que podemos realizar la operacin desde los tems del men de la ventana hija, el Sender podr ser otros cuatro controles ms. En el fuente 7 se ve cmo se discierne entre uno y otro y cmo se almacena, en la variable de tipo cadena Ch, el smbolo a utilizar.

// --- Fuente 7 -------------------------------------------------------procedure TVentanaCalculadora.PBOperar(Sender: TObject); begin if (Sender=PBSuma) or (Sender=SumaMnu) then Ch := '+'; if (Sender=PBResta) or (Sender=RestaMnu) then Ch := '-'; if (Sender=PBMult) or (Sender=MultMnu) then Ch := '*'; if (Sender=PBDiv) or (Sender=DivMnu) then Ch := '/'; nValor := StrToInt( Resul.Text ); Resul.Clear end;

7
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

Cuando se pincha el botn de igual (=) para obtener el resultado, o se elige el tem del men Igual a, se invoca al procedimiento PBIgualar, (ver fuente 8) en el cual se recurre a las dos variables pblicas nValor y Ch con los datos correctamente almacenados, adems se convierte a valor numrico el dato del control de edicin, se calcula convenientemente y se almacena el resultado en el control de edicin.

// --- Fuente 8 -------------------------------------------------------procedure TVentanaCalculadora.PBIgualar(Sender: TObject); var nActual: Integer; nCod: Integer; nResultado: Integer; begin Val( Resul.Text, nActual, nCod ); case Ch[1] of '+': nResultado := nValor + nActual; '-': nResultado := nValor - nActual; '*': nResultado := nValor * nActual; '/': nResultado := nValor div nActual; end; Resul.Text := IntToStr( nResultado ) end;

Otra mejora sera la de realizar la divisin con el operador /, la cual permite obtener decimales (lo cual obligara a tipificar la variable como real, no como integer)., en vez del operador div que resulta, para el ejemplo, tan cmodo como ineficaz.

Relacin entre ventanas


Una aplicacin MDI con ventanas hijas instancia, de manera automtica, al menos una de sus hijas. Hecho esto, y acto seguido, se pueden instanciar ms de la manera que se ha visto en el fuente 3. An as, podemos querer no instanciar ni una sola de ellas de manera automtica, sino dejar esta operacin al buen criterio del usuario. Para hacer esto hay que entrar en la opcin Options... del men Project, y en la carpeta Form desplazar del ListBox de la izquierda al de la derecha todas aquellas ventanas que no queramos lanzar automticamente. En nuestro caso slo hay que trasladar la ventana VentanaCalculadora (ver figura 3), pues slo tenemos un tipo de ventana hija.

8
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

Figura 3: Opciones del Proyecto

En lo que a mens se refiere, es habitual mezclar los de las ventanas hijas con el de la padre, haciendo que todos ellos convivan en la ventana marco. Para esto hay que manipular el dato GroupIndex del men, diciendo el nivel que cada men tiene. Por defecto, el valor de GroupIndex es 0, lo cual hara que los mens de las ventanas hijas, que tambin tienen un GroupIndex a 0 por defecto, reemplazara al de la ventana padre. Sin embargo, si al tem Ejecutar (ventana padre) le dejamos el GroupIndex a 0 y al tem Ventanas (tambin de la ventana padre) le reservamos un 9, nos estaremos asegurando de que el tem Ventanas siempre aparecer al final del men. Cuando ahora se instancie la ventana hija slo se reemplazar el tem Ejecutar, y se compartir el de Ventanas. Tambin esto se puede evitar asignando al GroupIndex de todos los tems de la ventana hija el valor 1, quedndonos el aspecto del men como se ve en la figura 4.

9
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

Figura 4: Mens compartidos entre ventanas

Para acabar de depurar el cdigo, diremos que si una ventana hija de una MDI es cerrada (por cualquiera de sus formas de hacerlo), sta no desaparece, sino que se iconiza hasta que la aplicacin general finalice. Si queremos cerrar la ventana y, adems, que sta desaparezca del todo hay que ensayar el cdigo del fuente 9, encargado de destruir el objeto y de liberar la totalidad de la memoria.

// --- Fuente 9 -------------------------------------------------------procedure TVentanaCalculadora.Liberar(Sender: TObject; var Action:TCloseAction); begin Action := caFree end;

En cualquier caso, y cuando se acabe la aplicacin, todas las ventanas hijas desaparecern, sin que el programador se tenga que encargar de recorrrselas cerrndolas o destruyndolas.

10
Algoritmo. La revista para el programador de sistemas de bases de datos. http://www.eidos.es - Grupo EIDOS

Das könnte Ihnen auch gefallen