Vous êtes sur la page 1sur 20

Capítulo 5

APLICACIONES CON INTERFAZ


GRAFICA TIPO WINDOWS

La aparición de los sistemas operativos con interfaces gráficas a disposición del


usuario común, sin lugar a dudas generó un salto gigantesco en el interés que por los
computadores tienen las personas. Este tipo de sistemas y sus aplicaciones han
desarrollado un nivel de abstracción tan elevado que todos los usuarios nos
preocupamos únicamente por la forma como podemos manipular los diferentes
elementos gráficos que visualizamos en la pantalla, antes que por los detalles de tipo
técnico relacionados con el funcionamiento interno de la máquina. Aunque hoy en día
son muchos los sistemas operativos que ofrecen un entorno gráfico para la interacción
entre la máquina y el usuario, y que Windows no es precisamente el pionero en este
campo, tampoco se puede desconocer que el aporte realizado por este sistema al
mundo de los entornos gráficos ha sido definitivo para la masificación del uso del
computador personal por parte de personas cuyos intereses no son precisamente los de
profundizar en esta ciencia, sino utilizar su computador como una herramienta mas, de
trabajo o recreación.
Dentro del campo de las aplicaciones con interfaz gráfica, el trabajo de programarlas
no ha sido tan sencillo como si lo es su manejo por parte del usuario final. El
mecanismo utilizado por Windows ha sido poner a disposición del programador un
conjunto de funciones, conocido como API (Aplication Programming Interface),
que le permiten manipular y comunicarse con el interior del sistema operarativo. Pero
en la mayoría de los casos, la comprensión del funcionamiento y manipulación de estas
funciones requiere una curva de aprendizaje muy elevada que hace demasiado lento el
desarrollo de este tipo de programas. El Framework .NET lo que ha hecho es
encapsular todas las funciones en un conjunto de clases que ofrecen al programador un
medio sencillo de acceder, entre otros, al sistema gráfico y los servicios del sistema
operativo, para de esta manera agilizar el tiempo utilizado en la programación de
aplicaciones con interfaz gráfica.
En el campo de las aplicaciones gráficas, las clases de .NET encapsulan todos los
mecanismos necesarios para construir los elementos gráficos más usuales que
conforman un programa de este tipo, comenzando por las ventanas, que son la base de
todo.

Un programa tipo Windows


Los programas desarrollados en los capítulos anteriores han basado su funcionamiento
en el objeto denominado consola y prácticamente, a excepción de los tres o cuatro
últimos ejemplos del anterior capítulo, todos se ejecutan en forma secuencial. El
sistema busca el método Main y lee todas las líneas en forma secuencial hasta llegar al
final de este método, punto en el cual la aplicación termina, o en el mejor de los casos
la ejecución ingresa a un ciclo y se mantiene en él hasta que por alguna razón pueda
salir del mismo. En algunos de estos programas se introdujeron algunos elementos con
interfaz gráfica, pero aun así las cosas no cambiaron mucho, ya que el sistema siempre
va en busca del final del método para dar por terminada la ejecución, y por ende no se
tiene mucho control sobre estas ventanas.
140 CAPITULO 5 PROGRAMACION CON C#

Un programa como el desarrollado en el capítulo 3 nos deja ver una ventana, pero si el
lector le pone cuidado observará que no es mucho lo que puede hacer con ese
elemento.

using System.Windows.Forms;
using System.Threading;

public class HolaVentana


{
static void Main()
{
Form ventana;
ventana = new Form();
ventana.Text = "Hola ventana...";
ventana.Show();
Thread.Sleep(5000);
}
}

Para poder visualizar la ventana ha sido necesario recurrir a un mecanismo de


congelamiento de la ejecución que impide por un instante llegar al final del método
Main.
Una característica fundamental de Windows es que se trata de un sistema operativo de
paso de mensajes. En el interior del sistema existe un mecanismo que convierte todos
los eventos en mensajes (o se puede decir, señales). Pero, en general, la ejecución de
una aplicación gráfica no es diferente a la de una aplicación de consola, o a la de las
viejas aplicaciones de entornos de solo texto. El truco consiste en hacer que la
ejecución de una aplicación ingrese a un bucle y se quede en él esperando a recibir y
procesar todos los mensajes que le envía el sistema operativo.
El lenguaje que mejor describe como funciona Windows es el lenguaje C, que bien
puede considerarse como la forma nativa de la programación Windows. Un ejemplo de
una pequeña aplicación con interfaz gráfica en C, permite visualizar el ciclo que obliga
a la ejecución del programa a permanecer a la espera de los mensajes.

#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstancia,
HINSTANCE d2, LPSTR d3, int d4)
{
MSG mensaje;
HWND manejador;

manejador = CreateWindow("BUTTON", "Hola ventana!",


WS_VISIBLE | BS_CENTER, 100, 100, 100,
80, NULL, NULL, hInstancia, NULL);

// Aquí inicia el ciclo


while (GetMessage(&mensaje, NULL, 0, 0))
{
if (mensaje.message == WM_LBUTTONUP)
{
DestroyWindow(manejador);
PostQuitMessage(0);
}
DispatchMessage(&mensaje); //recuperar mensaje
}
return mensaje.wParam;
}

www.pedrov.phpnet.us
CAPITULO 5 APLICACIONES CON INTERFAZ GRAFICA TIPO WINDOWS 141
El programa crea dos variables, una para controlar los mensajes y la otra para manejar
una ventana. Se crea una ventana, que incluye un botón de comando que la cubre en su
totalidad. Luego la ejecución ingresa en el ciclo while que se encarga de procesar los
mensajes, especialmente el mensaje identificado con la macro WM_LBUTTONUP, el
cual se produce cuando el usuario hace clic con el botón izquierdo del ratón sobre el
botón. Cuando ocurre esto último se destruye la ventana y se anula la recepción de
Figura 5.1: Programa con
mensajes. Un último detalle, el programa como tal no es orientado a objetos sino interfaz gráfica de usuario
estructurado, por que de hecho el sistema operativo ha sido desarrollado bajo este desarrollado en lenguaje C
con un bucle de mensaje
paradigma. simple.
Esta es la estructura interna que posee un programa que se ejecuta en el entorno gráfico
de Windows, y que .NET la encapsula en el conjunto de clases incluidas en el espacio
de nombres System.Windows.Forms. En este contexto, .NET puede considerarse
como una capa de software que se encarga de ocultar todos los detalles técnicos y
encapsularlos en clases que se encargan de manipular las funciones de la API y realizar
muchas tareas que son repetitivas de una aplicación a otra, en forma automática. Las
clases contenidas en este espacio de nombres le permiten al programador construir
interfaces gráficas de forma rápida y sencilla, incluyendo la gran mayoría de
componentes que forman parte de ellas, y que incluso se consideran ya unos estándares
de las aplicaciones gráficas. Adicional, el programador puede construir sus propios
componentes utilizando básicamente la herencia de clases.

Un programa tipo Windows con C# y .NET


Desde la perspectiva de C#, un programa con interfaz gráfica, que se ejecuta bajo el
sistema operativo Windows, es muy similar a un programa de consola. La única
diferencia, es que debe existir un bucle que se encargue de procesar todos los mensajes
del sistema operativo dirigidos a la aplicación. En este punto es donde, a diferencia del
lenguaje C, entra a operar la orientación a objetos mediante la encapsulación de este
bucle de mensajes y otras propiedades inherentes al mismo, en una clase que se
encarga de todos estos detalles. Esa clase se llama Application y es estática, lo que
significa que no es posible definir objetos a partir de ella.

La clase Application
La clase Application hace parte del espacio de nombres System.Windows.Forms. El
principal método que posee esta clase es Run, el cual se encarga de iniciar el bucle de
mensajes en la línea de ejecución que se encuentre actualmente.
El método Run está sobrecargado con tres versiones. Una de ellas se ejecuta sin
parámetros, la otra recibe un parámetro del tipo ApplicationContext, y una tercera
versión recibe un objeto del tipo Form, o lo que se conoce como formulario. La
mayoría de aplicaciones estándar de Windows se ejecutan bajo esta última versión del
método Run.

El formulario
El elemento principal y más representativo de una aplicación con interfaz gráfica es
aquel que se conoce con el nombre de ventana. Desde la visión del programador de C#,
el objeto que da origen a este elemento es el formulario.
La clase Form, que pertenece al espacio de nombres System.Windows.Forms, es
quien se encarga de definir todos los formularios que sean necesarios para la creación
de las ventanas que puede necesitar una aplicación con interfaz gráfica de usuario.
Generalmente, y en el contexto del entorno de desarrollo de .NET, a este tipo de
aplicaciones se le denomina programas Windows Forms.

pedrov.cs@hotmail.com
142 CAPITULO 5 PROGRAMACION CON C#

Form es una clase que encapsula todas las propiedades, métodos y eventos que se
necesitan para dar funcionalidad a una ventana. Pero esto no significa que el
programador tenga que limitarse a definir objetos con esta clase y a modificar sus
propiedades, por que también puede heredar de ella para crear clases que definan
formularios de ventanas totalmente personalizadas a sus intereses.

Ejemplo 5.1 Presentación de mi primer formulario

En un ejemplo, de un capitulo anterior, se desarrollo un programa que muestra un


ventana al estilo de Windows, pero fue necesario recurrir a un truco poco convencional
para obligar al sistema a que la mostrara por un instante en pantalla. Además,
observamos que dicha ventana solo se constituye en un dibujo con poca o ninguna
funcionalidad. No es posible moverla, maximizarla o al menos controlar en que
momento deseamos cerrarla.
En el siguiente ejemplo vamos a mostrar una ventana totalmente autónoma, cuyo
comportamiento es idéntico al de cualquier otra ventana que el lector conoce en otros
programas de Windows. La diferencia con el anterior ejemplo, radica en la inclusión de
un bucle de mensajes a través de la clase Application.

/* Archivo: Ejemplo51.cs */

using System.Windows.Forms;

public class ProgramaGrafico


{
static void Main()
{
Form ventana = new Form();
ventana.Text = "¡Hola ventana...!";
ventana.Visible = true;
Application.Run(ventana);
}
}

Antes de ingresar a programar en un entorno de desarrollo integrado, como


Sharpdevelop o Visual C#, es recomendable que el lector programe este y los dos o
tres ejemplos que vienen en seguida en un editor de texto sencillo, y los compile
mediante la línea de comandos. Esto le permitirá conocer a fondo como funcionan
estos entornos y también identificar como organizan los archivos fuente de una
aplicación.
Por ahora compile este programa con la instrucción,

> csc ejemplo51.cs

Al ejecutar el programa se muestra en pantalla una ventana, que aunque vacía, es


totalmente funcional. Ahora ya es posible maximizarla, restaurarla, minimizarla o
modificar su tamaño con el ratón. Pero aún existe un detalle, y es que su ejecución
sigue dependiendo de la consola. Y sino, pruebe lo siguiente: ejecute el Explorador de
Windows, busque el programa que acaba de compilar, ejemplo51.exe, y haga doble clic
sobre él. Observará que debajo de la ventana se carga también la consola.
El problema anterior, si es que se puede llamar problema, únicamente radica en una
opción del compilador. Por defecto este compila los archivos fuente como programas
de consola. Si se quiere informarle que el programa va a trabajar en el entorno gráfico
de Windows es necesario indicárselo mediante el parámetro /target:winexe, así:

www.pedrov.phpnet.us
CAPITULO 5 APLICACIONES CON INTERFAZ GRAFICA TIPO WINDOWS 143
> csc /t:winexe ArchivoFuente.cs

Vuelva a compilar el programa de nuestro ejemplo mediante la instrucción,

> csc /t:winexe ejemplo51.cs

Si realiza las pruebas del caso observará que la ventana se muestra totalmente libre. Ya
no existe la consola que la acompaña. Incluso si se ejecuta mediante una llamada al
ejecutable, ejemplo51.exe, el lector observará que inmediatamente se devuelve el
control a la línea de comandos. Algo que no ocurría en la anterior compilación.
Y con esto, por ahora solo podemos decir, ¡bienvenido a las aplicaciones gráficas bajo
el entorno Windows!

Aplicaciones con ventana principal


La aplicaciones que se ejecutan en Windows generalmente están constituidas por una o
varias ventanas, pero siempre va existir una ventana que actúa como la base de las
demás, o lo que podemos llamar una ventana principal. Esta ventana principal es quien
se encarga de servir como base para que el usuario pueda controlar toda la aplicación.
Esa parece ser la lógica del cerebro humano, las cosas son más fáciles si existe un
centro de mandos desde donde se pueda interactuar con todas las funcionalidades que
tiene un sistema. Y sino miremos como se manejan todas las máquinas que hemos
creado.
Aunque pueden programarse aplicaciones donde no haya ninguna ventana que actué
como centro de control, se ha comprobado que generalmente este tipo de aplicaciones
resulta de difícil comprensión y manejo hasta para los usuarios más experimentados.
Por esa razón, la ingeniería de software ha adoptado el diseño de aplicaciones
basándose en una ventana principal.

Ejemplo 5.2 La ventana principal

El programa que viene a continuación crea dos ventanas y las muestra en pantalla. Una
de ellas se muestra a través de la propiedad Visible, y la otra lo hace automáticamente
al asignarse como parámetro del método Run.

/* Archivo: Ejemplo52.cs */

using System;
using System.Windows.Forms;

public class DobleVentana


{
static void Main()
{
Form formPrincipal = new Form();
Form formVentana = new Form();

formVentana.Visible = true;
formVentana.Text = "formVentana";
formPrincipal.Text = "formPrincipal";

Application.Run(formPrincipal);
}
}

Compile el programa con la instrucción,

pedrov.cs@hotmail.com
144 CAPITULO 5 PROGRAMACION CON C#

> csc /t:winexe ejemplo52.cs

Para comprender la lógica de la ejecución es importante que el lector corra el programa


varias veces. Al ejecutarlo se muestran en pantalla las dos ventanas, que en apariencia
son iguales en cuanto a funcionalidad. Sin embargo, si se cierra primero la ventana
formVentana se observa que la otra ventana no se ve afectada en absoluto. Pero si se
cierra primero la ventana formPrincipal, vemos que también se cierra la ventana
formVentana.
Lo anterior nos lleva a concluir que el formulario que se pasa como argumento al
método Run actúa como ventana principal de una aplicación y cuando ella se cierra,
también cierra a las demás ventanas que la conforman, y de hecho da por terminada la
ejecución del bucle de mensajes.
Aunque está no es la única forma de diseñar y programar una aplicación en C#, si es la
más conveniente y también las más utilizada en las aplicaciones de uso general.
Además, en este principio se basan los entornos de desarrollo integrado para organizar
el código de las aplicaciones estándar de Windows. Es muy importante que el lector
tenga presente que Sharpdevelop y Visual C#, en el caso de las aplicaciones tipo
Windows, siempre organizan el código de programación a partir de un formulario
principal. Por defecto Sharpdevelop nombra al formulario principal con el identificador
MainForm, mientras que Visual C# lo llama Form1.

Ejemplo 5.3 Una ventana con eventos

En este punto el lector ya ha desarrollado algunos ejemplos sobre implementación y


control de eventos en una aplicación. Las clases que definen objetos visuales
implementan una gran cantidad de eventos y el trabajo del programador de .NET es
desarrollar los métodos que los controlen. El siguiente programa muestra dos eventos
que han sido controlados para mostrar un mensaje en pantalla. El evento Load que se
genera cada que se está iniciando el proceso de carga de una ventana y el evento Click
que se genera al hacer clic con el botón principal del ratón sobre la ventana.

/* Archivo: Ejemplo53.cs */

using System;
using System.Windows.Forms;

public class VentanaEventos


{
static void Main()
{
Form formVentana = new Form();
formVentana.Load += new EventHandler(FormVentanaLoad);
formVentana.Click += new EventHandler(FormVentanaClick);
formVentana.Text = "Ventana";
Application.Run(formVentana);
}

static void FormVentanaLoad(object emisor, EventArgs e)


{
MessageBox.Show("Cargando...", "Load");
}
static void FormVentanaClick(object emisor, EventArgs e)
{
MessageBox.Show("Clic...", "Click");
}
}

www.pedrov.phpnet.us
CAPITULO 5 APLICACIONES CON INTERFAZ GRAFICA TIPO WINDOWS 145
Compile el programa con la instrucción,

> csc /t:winexe ejemplo53.cs

El ejecutar el programa vemos que antes de aparecer la ventana en pantalla se ejecuta


el evento Load. Esta característica permite utilizar este evento para configurar la
ventana a los requerimientos de la aplicación, antes que se visualice por el usuario.

Agregar controles a una ventana


En Windows se le llama control a cualquier elemento gráfico colocado sobre una
ventana y que permite realizar alguna tarea de interés para la aplicación. Ejemplos de
controles son las barras de desplazamiento, los menús, botones de comando, botones
de opción (o radio), casillas de verificación, campos de entrada de texto y cuadros de
lista, entre otros. Los controles son una forma de abstracción y encapsulamiento
bastante elevado que le permiten al programador estructurar y modular sus
aplicaciones, despreocupándose de los detalles relacionados con el manejo del teclado
y el ratón.
Para .NET cualquier control es un objeto que puede crearse a partir de una clase, y su
manejo es igual al de cualquier otro objeto que el programador haya utilizado con
anterioridad. Con la ventaja que ya existe una amplia gama de clases que han sido
programadas, y hacen parte del Framework .NET, para tal fin. Aunque este tema se va
a describir con más detalle en posteriores capítulos, aquí se hace mención de tres clases
que permiten crear los controles más básicos de una aplicación: Button, para crear
botones de comando; TextBox, para crear campos de entrada de texto, y Label para
crear las llamadas etiquetas, que permiten mostrar cadenas de texto sobre la ventana.
Las tres clases mencionadas exponen un conjunto de propiedades que son comunes a
todos sus objetos. Entre ellas están las siguientes:

Propiedad Descripción

Text Permite escribir o leer una cadena de texto hacia o desde el control

Left Establece o recupara la coordenada horizontal de la esquina superior


izquierda del control

Top Establece o recupera la coordenada vertical de la esquina superior izquierda


del control

Width Establece o recupera el ancho de un control

Height Establece o recupera el alto de un control

Las propiedades de posición y dimensión de un control aceptan valores enteros que por
defecto representan cantidades de píxeles.

Ventana

Top

Left

Height

Width

Figura 5.2: Top y Left son las coordenadas de la esquina superior izquierda, y
Width y Height las dimensiones de ancho y alto de un control.
pedrov.cs@hotmail.com
146 CAPITULO 5 PROGRAMACION CON C#

Estas propiedades igual existen para un formulario, donde Left y Top establecen o
devuelven las coordenadas de la esquina superior izquierda con respecto a la pantalla.
El formulario expone la propiedad Controls, que es un objeto del tipo
CollectionControls, el cual expone el método Add que permite agregar un control a la
ventana. Su sintaxis es la siguiente:

Formulario.Controls.Add(Identificador);

El parámetro del método Add, es el identificador de la variable que representa al


objeto control.

Ejemplo 5.4 Una ventana y un botón

A continuación se muestra un programa formado por una ventana que contiene un


botón etiquetado con Aceptar. El programa hace una implementación del evento Click
del botón.

/* Archivo: Ejemplo54.cs */

using System;
using System.Windows.Forms;

public class ProgramaGrafico


{
static void Main()
{
Form formVentana = new Form();
Button buttonAceptar = new Button();
// Botón Aceptar
buttonAceptar.Click += new EventHandler(ButtonAceptarClick);
buttonAceptar.Text = "Aceptar";
buttonAceptar.Left = 100;
buttonAceptar.Top = 150;
// Configurar la ventana
formVentana.Text = "Ventana";
formVentana.Visible = true;
// Agregar un control a la ventana
formVentana.Controls.Add(buttonAceptar);
// Entrar al bucle de mensajes
Application.Run(formVentana);
}

// Método que controla el evento Click del botón Aceptar


static void ButtonAceptarClick(object sender, EventArgs e)
{
MessageBox.Show("¡Hola botón...!", "Click");
}
}

Ejemplo 5.5 Interfaz gráfica con un único controlador de eventos

El programa de este ejemplo muestra cuatro botones de comando que generan el


evento Click y este es controlado por un único evento. Esta es una buena forma de
programar un conjunto de controles que realizan tareas muy similares.
Se ha implementado el controlador del evento Click de los cuatro botones mediante el
método,
www.pedrov.phpnet.us
CAPITULO 5 APLICACIONES CON INTERFAZ GRAFICA TIPO WINDOWS 147
static void ButtonOperar(object emisor, EventArgs e)
{
Button buttonEmisor = (Button)emisor;
MessageBox.Show(buttonEmisor.Text);
}

Sabemos que el primer parámetro del método establece quién ha sido el objeto que ha
generado el evento. En este caso se identifica mediante el título del botón, pero para
poder leer este titulo es necesario hacer una conversión de tipos, o cast, al objeto
emisor, convirtiéndolo al tipo Button.

/* Archivo: Ejemplo55.cs */

using System;
using System.Windows.Forms;

public class Operatoria


{
static void Main()
{
Form formVentana = new Form();

Button buttonSumar = new Button();


buttonSumar.Click += new EventHandler(ButtonOperar);
buttonSumar.Text = "Sumar";
buttonSumar.Left = 50;
buttonSumar.Top = 100;
formVentana.Controls.Add(buttonSumar);

Button buttonRestar = new Button();


buttonRestar.Click += new EventHandler(ButtonOperar);
buttonRestar.Text = "Restar";
buttonRestar.Left = 175;
buttonRestar.Top = 100;
formVentana.Controls.Add(buttonRestar);

Button buttonMultiplicar = new Button();


buttonMultiplicar.Click += new EventHandler(ButtonOperar);
buttonMultiplicar.Text = "Multiplicar";
buttonMultiplicar.Left = 50;
buttonMultiplicar.Top = 150;
formVentana.Controls.Add(buttonMultiplicar);

Button buttonDividir = new Button();


buttonDividir.Click += new EventHandler(ButtonOperar);
buttonDividir.Text = "Dividir";
buttonDividir.Left = 175;
buttonDividir.Top = 150;
formVentana.Controls.Add(buttonDividir);

Application.Run(formVentana);
}

static void ButtonOperar(object emisor, EventArgs e)


{
Button buttonEmisor = (Button)emisor;
MessageBox.Show(buttonEmisor.Text);
}
}

pedrov.cs@hotmail.com
148 CAPITULO 5 PROGRAMACION CON C#

Al ejecutar el programa se muestra en pantalla una ventana con cuatro botones


marcados con las operaciones aritméticas básicas. Como el lector puede darse cuenta,
este programa no hace prácticamente nada importante, lo único es mostrar la forma de
controlar mediante un único método los eventos generados por varios controles.
Además ha exigido una tediosa cantidad de código con el único objetivo de configurar
los controles. ¡Ya va siendo hora de recurrir a un generador automático de código!

Formularios por herencia


Las prácticas de programación realizadas hasta ahora han mostrado ventanas creadas
con formularios definidos directamente de la clase Form, estableciendo sus
propiedades y controladores de eventos en el método Main. Sin embargo esta no es la
metodología utilizada en la mayoría de aplicaciones gráficas, especialmente en
aquellas diseñadas con la ayuda de los entornos integrados de desarrollo.
La mejor metodología consiste en construir una clase que defina un formulario con las
conveniencias requeridas por el programador. Esto se logra mediante la aplicación de
la herencia de clases y la inclusión, a través de su constructor, de los elementos de
software necesarios para la ventana definitiva.
El formulario principal de la aplicación debe heredarse de una clase Form, y en su
constructor deben agregarse los controles necesarios para la ventana que se generará a
partir de él. En el método Run de Application se debe incluir una instancia de este
formulario. En adelante todo el trabajo de construcción visual se realiza sobre la clase
que define el formulario principal, dejando al método Main, únicamente la tarea de
marcar el punto de inicio de la aplicación.
El siguiente esquema muestra como se debe construir las clases básicas de una
aplicación gráfica utilizando herencia de Form:

public class NombrePrograma


{
static void Main(string[] argumentos)
{
// [Llamadas de inicio]
Application.Run(new FormularioPrincipal)
// [Llamadas de finalización]
}
}

public class FormularioPrincipal : Form


{
public FormularioPrincipal()
{
// Llamada a un método de inicialización
}
}

Si la aplicación consta de varios formularios, para cada uno de ellos debe


implementarse una clase heredada de Form y en ella deben incluirse sus controles.
Generalmente la tarea de inclusión de controles en cada clase se asigna a un método
privado.

Ejemplo 5.6 Heredando un formulario

El siguiente programa muestra la creación de un formulario a partir de una clase


heredada de Form. En el constructor de de la clase se incluye un método que se
encarga de agregar un botón a la ventana.

www.pedrov.phpnet.us
CAPITULO 5 APLICACIONES CON INTERFAZ GRAFICA TIPO WINDOWS 149

/* Archivo: Ejemplo56.cs */

using System;
using System.Windows.Forms;

public class AplicacionVentanas


{
static void Main()
{
Application.Run(new FormularioPrincipal());
}
}

public class FormularioPrincipal : Form


{
public FormularioPrincipal()
{
InicializarComponente();
}

private void InicializarComponente()


{
Button buttonAceptar = new Button();
buttonAceptar.Text = "Aceptar";
buttonAceptar.Left = 100;
buttonAceptar.Top = 100;

this.Text = "Ventana principal";


this.Controls.Add(buttonAceptar);
}
}

Un aspecto importante que no debe confundir al lector es que se ha establecido como


parámetro del método Run una instancia del formulario sin identificador explicito.
Esta solo es una forma de simplificar el código, por que igual pudo haberse definido
una instancia explicita antes del método, para luego y asignarse su identificador como
parámetro.
Aunque en apariencia, el ejecutarla la aplicación parece igual a las desarrolladas en una
única clase, en realidad este tipo de aplicaciones contiene mayor versatilidad. Un
aspecto limitante en las anteriores aplicaciones es que el método Main exige siempre
interactuar con métodos estáticos, lo cual limita enormemente la funcionalidad de una
clase. Además no podemos perder de vista que las aplicaciones reales deben
conformarse a partir de componentes independientes unos de otros, una característica
clave de las modernas aplicaciones de software.

Ejemplo 5.7 Aplicación con eventos que realizan operaciones

En el ejemplo 5.5 desarrollamos un programa con una interfaz gráfica sobre


operaciones aritméticas, pero que solo se limitaba a responder a los eventos Click de
cada botón. La razón obvia era que no había ingreso de valores, pero así los hubiera
habido la verdadera razón es que al trabajar con métodos estáticos y sobre una sola
clase es casi imposible pasar datos entre dichos métodos. La solución es rediseñar la
aplicación para poder pasar datos a los métodos que controlan a los eventos de los
botones y esto solo se logra con una clase no estática.

pedrov.cs@hotmail.com
150 CAPITULO 5 PROGRAMACION CON C#

En este ejemplo vamos a aplicar la metodología de herencia de formularios para


rediseñar la aplicación que nos permita realizar operaciones aritméticas con valores
ingresados por el usuario a través de cajas de texto.
La ventana principal de la aplicación se va definir por medio de un formulario
heredado de Form. Su parte básica es como sigue:

public class FormularioPrincipal : Form


{
// Controles de la ventana
TextBox textNumero1;
TextBox textNumero2;
Label labelResultado;
Button buttonSumar;
Button buttonRestar;
Button buttonMultiplicar;
Button buttonDividir;

// Constructor
public FormularioPrincipal()
{
InicializarComponente();
}

// Método para colocar controles en la ventana


void InicializarComponente()
{
// Crear y agregar controles a la ventana
}

// Méotodos para controlar los eventos Click


void ButtonSumarClick(object emisor, EventArgs e)
{
// Método para controlar el evento click del
// botón Sumar
}

void ButtonRestarClick(object emisor, EventArgs e)


{
// Método para controlar el evento click del
// botón Restar
}

void ButtonMultiplicarClick(object emisor, EventArgs e)


{
// Método para controlar el evento click del
// botón Multiplicar
}

void ButtonDividirClick(object emisor, EventArgs e)


{
// Método para controlar el evento click del
// botón Dividir
}
}

Los controles de la ventana se han definido en el ámbito de toda la clase, para de esta
hacerlos accesibles a todos los métodos que los requieran, en especial a los métodos
controladores de los eventos.

www.pedrov.phpnet.us
CAPITULO 5 APLICACIONES CON INTERFAZ GRAFICA TIPO WINDOWS 151
Se han implementado métodos diferentes para controlar los eventos de cada botón. La
razón, únicamente se quiere mostrar que existen muchas formas de controlar un
evento. En la práctica hubiera sido mejor utilizar la técnica del ejemplo 5.5, un método
para todos los eventos, pero la práctica es quien hace al maestro.
En definitiva el programa que permite realizar operaciones aritméticas queda como
sigue:

/* Archivo: Ejemplo57.cs */

using System;
using System.Windows.Forms;

public class Programa


{
static void Main()
{
FormularioPrincipal formPrincipal = new FormularioPrincipal();
Application.Run(formPrincipal);
}
}

// Clase que definirá la ventana principal


public class FormularioPrincipal : Form
{
// Controles de la ventana
TextBox textNumero1;
TextBox textNumero2;
Label labelResultado;
Button buttonSumar;
Button buttonRestar;
Button buttonMultiplicar;
Button buttonDividir;
// Constructor
public FormularioPrincipal()
{
InicializarComponente();
}
// Método para crear y colocar los controles en la ventana
void InicializarComponente()
{
// Configurar la ventana
this.Text = "Operatoria";
this.Height = 250;

// Colocar los controles


textNumero1 = new TextBox();
textNumero1.Left = 100;
textNumero1.Top = 20;
this.Controls.Add(textNumero1);

textNumero2 = new TextBox();


textNumero2.Left = 100;
textNumero2.Top = 40;
this.Controls.Add(textNumero2);

labelResultado = new Label();


labelResultado.Left = 100;
labelResultado.Top = 60;
labelResultado.Text = "0";
this.Controls.Add(labelResultado);

pedrov.cs@hotmail.com
152 CAPITULO 5 PROGRAMACION CON C#

buttonSumar = new Button();


buttonSumar.Click += new EventHandler(ButtonSumarClick);
buttonSumar.Text = "Sumar";
buttonSumar.Left = 50;
buttonSumar.Top = 100;
this.Controls.Add(buttonSumar);

buttonRestar = new Button();


buttonRestar.Click += new EventHandler(ButtonRestarClick);
buttonRestar.Text = "Restar";
buttonRestar.Left = 175;
buttonRestar.Top = 100;
this.Controls.Add(buttonRestar);

buttonMultiplicar = new Button();


buttonMultiplicar.Click += new EventHandler(ButtonMultiplicarClick);
buttonMultiplicar.Text = "Multiplicar";
buttonMultiplicar.Left = 50;
buttonMultiplicar.Top = 150;
this.Controls.Add(buttonMultiplicar);

buttonDividir = new Button();


buttonDividir.Click += new EventHandler(ButtonDividirClick);
buttonDividir.Text = "Dividir";
buttonDividir.Left = 175;
buttonDividir.Top = 150;
this.Controls.Add(buttonDividir);

// Controles particulares de etiquetas


Label labelA = new Label();
labelA.Text = "a =";
labelA.Left = 80;
labelA.Top = 20;
this.Controls.Add(labelA);

Label labelB = new Label();


labelB.Text = "b =";
labelB.Left = 80;
labelB.Top = 40;
this.Controls.Add(labelB);

Label labelC = new Label();


labelC.Text = "c =";
labelC.Left = 80;
labelC.Top = 60;
this.Controls.Add(labelC);
}

// Métodos controladores de los eventos Click de los botones

void ButtonSumarClick(object emisor, EventArgs e)


{
double a = Convert.ToDouble(textNumero1.Text);
double b = Convert.ToDouble(textNumero2.Text);
double c = a + b;
labelResultado.Text = c.ToString();
}

www.pedrov.phpnet.us
CAPITULO 5 APLICACIONES CON INTERFAZ GRAFICA TIPO WINDOWS 153

void ButtonRestarClick(object emisor, EventArgs e)


{
double a = Convert.ToDouble(textNumero1.Text);
double b = Convert.ToDouble(textNumero2.Text);
double c = a - b;
labelResultado.Text = c.ToString();
}

void ButtonMultiplicarClick(object emisor, EventArgs e)


{
double a = Convert.ToDouble(textNumero1.Text);
double b = Convert.ToDouble(textNumero2.Text);
double c = a * b;
labelResultado.Text = c.ToString();
}

void ButtonDividirClick(object emisor, EventArgs e)


{
double a = Convert.ToDouble(textNumero1.Text);
double b = Convert.ToDouble(textNumero2.Text);

if (b != 0)
{
double c = a / b;
labelResultado.Text = c.ToString();
}
else
labelResultado.Text = "(Error...)";
}
}

Aunque aun hay programadores que creen que la programación es importante por el
número de líneas que tengamos que escribir manualmente, la verdad es que cuando se
trata de aplicaciones gráficas, la mayor parte del tiempo se pierde en programar la
configuración de los componentes. Este ejemplo es un claro modelo de por que los
entornos integrados de desarrollo son importantes a la hora de ayudarnos a generar el
repetitivo código de configuración visual para permitirnos dedicar más tiempo a lo
verdaderamente esencial, la programación de la funcionalidad de nuestra aplicación.
Por ahora lo que se busca es sentar bien las bases que nos permitan comprender cual es
el trabajo de los generadores de código para de esta manera, en un determinado
momento, saber donde es necesario hacer los cambios que nos permitan desarrollar una
aplicación ajustada a unos objetivos bien claros.

Como trabajan los IDE


Con base en lo descrito en las secciones anteriores podemos sacar las siguientes
conclusiones que se convierte en reglas de diseño para aplicaciones con interfaz gráfica
de usuario:
- Toda aplicación consta de un método Main, que es el punto de entrada para la
ejecución.
- Las aplicaciones con interfaz gráfica de usuario necesitan ingresar la ejecución
a un bucle de mensajes que permite escuchar y procesar todos los mensajes
provenientes del sistema operativo.
- El formulario enviado al bucle de mensajes, que .NET lo genera por medio del
método Run de la clase estática Application, se convierte en un formulario
principal que controla toda la aplicación.
pedrov.cs@hotmail.com
154 CAPITULO 5 PROGRAMACION CON C#

- Las ventanas se diseñan mejor construyendo clases heredadas de Form que


permitan definir formularios modificados que incluyen todos los controles
necesarios para su funcionamiento.
Estas pautas son las que tienen en cuenta los entornos integrados de desarrollo, IDE,
para organizar el código de los componentes que hacen parte de una aplicación básica.
Entornos como Sharpdevelop y Visual C# incluyen todos los componentes dentro de
un espacio de nombres que lleva el nombre del proyecto definido por el programador.
La clase con el método Main se almacena en un archivo fuente independiente, y la
clase que define a un formulario se guarda en dos archivos. Un archivo que incluye
únicamente el método de creación de controles y todos los elementos visuales que
hacen parte del diseño de la ventana. En un segundo archivo se incluye toda la
funcionalidad de la ventana y sus controles.

Punto de inicio,
Main

Diseño de la Funcionalidad
ventana de la ventana

Figura 5.3: Enfoque utilizado por Sharpdevelop y Visual C# para organizar en archivos, *.cs, el código
fuente de una aplicación conformada por un formulario que define una ventana al estilo Windows.

Para incluir la definición de una clase en dos archivos diferentes se utiliza la palabra
clave partial, que permite incluir implementaciones parciales en cada uno de ellos, las
cuales al momento de la compilación son unidas por el compilador en una sola clase.
El siguiente es un esquema general que muestra la funcionalidad de partial:

public partial class NombreClase


{
public NombreClase()
{
// Implementación del Constructor
}
}

public partial class NombreClase


{
// Otros miembros de la clase
}

En los entornos de desarrollo, por cada formulario que se defina en una aplicación se
generarán dos archivos fuente básicos. El contenido de uno de esos archivos, el que

www.pedrov.phpnet.us
CAPITULO 5 APLICACIONES CON INTERFAZ GRAFICA TIPO WINDOWS 155
corresponde al diseño de la ventana, es generado automáticamente a medida que se
hacen cambios en el diseñador gráfico que sirve como ayudante a la hora de construir
un formulario.
Los anteriores archivos no son las únicas fuentes que conforman una aplicación con
interfaz gráfica, pues existen algunos otros que permiten incluir información
importante para la aplicación o incluir recursos adicionales, como íconos y otros
elementos que ayudan a mejorar la calidad de la aplicación en desarrollo. Estos se
describirán con detalle en el siguiente capítulo, cuando se describa la programación
con un entorno de desarrollo integrado.

Ejemplo 5.8 Una aplicación, varias fuentes

Con este ejemplo vamos a mostrar como se organiza el código del código de
programación, de una aplicación con interfaz gráfica, en los entornos de desarrollo
integrado. Tomaremos como base a Sharpdevelop, pero cualquier otro entorno,
incluyendo a Visual C#, maneja un esquema similar.
Lo primero que hace el entorno de programación es crear una carpeta o directorio para
almacenar los archivos fuente. Esta carpeta se identifica con el nombre del proyecto.
En nuestro caso al proyecto lo llamaremos Ejemplo58. El lector debe crear en la
carpeta que ha venido utilizando como carpeta de ejercicios, una subcarpeta con el
nombre Ejemplo58.
Estos entornos, generalmente colocan la clase de programa, que incluye al método
Main, en un archivo fuente independiente, al cual se lo identifica como Programa.cs
(o comúnmente escrito en inglés como Program.cs). Todas las clases que hacen parte
de una aplicación se incluyen en un espacio de nombres que lleva el nombre del
proyecto.
Programe el siguiente archivo fuente y guárdelo en la carpeta de nuestro proyecto.

/* Archivo: Programa.cs */

using System;
using System.Windows.Forms;

namespace Ejemplo58
{
public class Programa
{
static void Main(string[] argumentos)
{
Application.Run(new VentanaPrincipal());
}
}
}

Cada ventana que conforma la aplicación se genera a partir de al menos dos archivos
fuente. En el primero de ellos se incluye el método de creación de controles y toda la
configuración de la ventana y se lo llama archivo del diseñador. Así, si la ventana se
llama VentanaPrincipal (o en inglés, MainForm) se genera un archivo con el nombre
VentanaPrincipal.Disenador.cs.
En el archivo del diseñador se incluye una parte de la clase que genera a la ventana,
por lo que es necesario utilizar la palabra clave partial en su definición. No se debe
olvidar que esta clase siempre se deriva de la clase Form.
El siguiente archivo fuente muestra la creación de una ventana que incluye un botón de
comando etiquetado con la palabra Aceptar, que aparece centrado en la ventana.
pedrov.cs@hotmail.com
156 CAPITULO 5 PROGRAMACION CON C#

/* Archivo: VentanaPrincipal.Disenador.cs */

using System;
using System.Windows.Forms;

namespace Ejemplo58
{
partial class VentanaPrincipal : Form
{
void InicializarComponente()
{
this.Text = "Ejemplo 58";

// Botón Aceptar
Button buttonAceptar = new Button();
buttonAceptar.Text = "Aceptar";
buttonAceptar.Left = (this.Width - buttonAceptar.Width) / 2;
buttonAceptar.Top = (this.Height - buttonAceptar.Height) / 2;
buttonAceptar.Click += new EventHandler(buttonAceptarClick);
this.Controls.Add(buttonAceptar);
}
}
}

El código que da funcionalidad a la ventana y todos sus controles se guarda en un


archivo fuente que lleva el nombre de la ventana. En este caso el archivo sería
nombrado como VentanaPrincipal.cs. En este archivo se incluye la parte de la clase
que tiene mayor interés para el programador por que la mayor parte de su trabajo se
centra en escribir código sobre este archivo.
De principio, el archivo de ventana incluye el constructor de clase, quién se encarga de
hacer una llamada al método de creación de controles. Este archivo tiene un aspecto
como el siguiente:

/* Archivo: VentanaPrincipal.cs */

using System;
using System.Windows.Forms;

namespace Ejemplo58
{
public partial class VentanaPrincipal : Form
{
public VentanaPrincipal()
{
InicializarComponente();
}
// Aquí se incluye toda la funcionalidad de la ventana
void buttonAceptarClick(object emisor, EventArgs e)
{
MessageBox.Show("Bienvenido...", "Ejemplo 58");
}
}
}

Todos los archivos fuente que conforman un proyecto son compilados en un único
ensamblado, que para este caso es un ejecutable, que lleva el nombre del espacio de
nombres que envuelve a las clases.
Para compilar nuestro proyecto utilice la instrucción,
www.pedrov.phpnet.us
CAPITULO 5 APLICACIONES CON INTERFAZ GRAFICA TIPO WINDOWS 157

> csc /t:winexe /out:Ejemplo58.exe ejemplo58\*.cs

Aunque estos no son los únicos archivos que conforman una aplicación con interfaz
gráfica de usuario, desarrollada mediante un entorno integrado de desarrollo, si son los
archivos más importantes que todo programador debe conocer y saber modificar
adecuadamente para lograr sacar el mayor provecho posible a este tipo de sistemas de
programación. Los dos primeros archivos son generados en forma automática por el
sistema de programación, pero es muy importante conocer bien su estructura de tal
manera que puedan ser manipulados con propiedad en el momento de realizar las
modificaciones que convengan al interés del programador.
Generalmente, los entornos integrados de desarrollo son buenos asistentes cuando se
trata de desarrollar un nivel medio de programación, pero pueden complicar las cosas,
e incluso limitarlas, cuando se trata de realizar programación de nivel avanzado.
Únicamente el pleno conocimiento de la forma como esta organizada la codificación
permite lograr los objetivos propuestos en un proyecto que requiera recurrir a
programación avanzada.

pedrov.cs@hotmail.com
158 CAPITULO 5 PROGRAMACION CON C#

www.pedrov.phpnet.us

Vous aimerez peut-être aussi