Formulario Splash
[Una agenda realizada en C#]

Fecha: 30 de junio de 2004
Autor: Antonio Cuesta Garcia [email protected]

 

Nota 07/Jul/04:
Tambi�n est� la versi�n para VB .NET


Introducci�n:
Comencé este articulo con la intenci�n de explicar la realizaci�n de un Formulario Splash, es decir un formulario inicial como el que aparece en la mayor�a de las aplicaciones comerciales con la informaci�n referente a la empresa, etc. y adem�s a�adir a este un hilo (Thread) donde se ejecuten funciones de inicializaci�n, sin que afecten a la visualizaci�n de dicho formulario.

Pero esta idea inicial en si era muy sosa, así que le a�adí un poco de funcionalidad al proyecto para que el resultado fuera mas interesante a todos aquellos que quieran leer este articulo. Creando al final una peque�a agenda, que a pesar de no parecer muy vistosa en ejecuci�n, si se puede observar en el c�digo la aplicaci�n de t�cnicas muy variadas como son la programaci�n en tres capas, programaci�n multiproceso, trabajo con ficheros XML y DataSets.

Por esta peque�a evoluci�n del proyecto inicial he dividido el articulo en dos partes:

Creaci�n de un Formulario Splash y ejecuci�n de un subproceso

Desarrollo de una agenda aplicando la programaci�n en tres capas (Interfaz de usuario, Capa de negocios, Capa de acceso a datos).



Bueno pues una vez que se ha explicado un poco la idea, lo mejor es ver el desarrollo.



Creaci�n de un Formulario Splash y ejecuci�n de un subproceso

Un formulario inicial de presentaci�n en una aplicaci�n es algo muy simple y que le da a la misma un toque muy profesional, esta se puede realizar de muchas maneras, así que yo simplemente intentare dar una breve introducci�n.

El Formulario Splash.

Primero creamos un nuevo proyecto de Aplicaci�n para Windows (en mi caso esta realizado en C#), y que yo he llamado FormSplash, de este proyecto el Form1.cs (Formulario inicial creado por defecto), será el formulario inicial de la aplicaci�n, que mas tarde se usara para contener la agenda (ya que solo necesitara un formulario).

A este proyecto le a�adiremos un nuevo formulario que yo he llamado FrmSplash, y que será nuestro formulario inicial.

Despu�s modifico las siguientes propiedades del formulario:

Pongo ControlBox a false y Text se deja en blanco para eliminar el titulo del formulario.

Pongo en StartPosition, el valor CenterScreen para que aparezca en el centro de la pantalla.

A ShowInTaskBar le doy el valor false, para que no aparezca el formulario en la barra de herramientas de Windows.

Como no queremos que el usuario modifique la ventana, ni que la minimice ni maximice, ya que queremos que este lo vea igual que nosotros (ya que puede ser nuestra peque�a obra de arte), ponemos el valor false en las propiedades MinimizeBox y MaximizeBox, y a FormBorderStyle le daremos el valor FixedSingle.

A partir de esto, lo mejor que yo puedo a�adir es simplemente que se "decore" al gusto, en el fichero adjunto que es el c�digo fuente completo se vera mejor la idea.

Una vez terminado el formulario, se le a�ade un control Timer, que será el encargado de que nuestro formulario este visible durante un cierto periodo de tiempo y desaparezca, dejando paso a la nuestra aplicaci�n (que realmente será lo importante).

A la hora de indicar el intervalo de tiempo lo podemos hacer de dos formas, una es simplemente indicarlo en el tiempo de dise�o, y otra puede ser indicada en tiempo de ejecuci�n, yo que he inclinado por la segunda opci�n, ya que si queremos reutilizar esta pantalla lo mejor es hacerlo así.

Para indicar el intervalo la idea que a mi se me ocurre es modificar el constructor por defecto de nuestro formulario y a�adirle un argumento que será un int que representara los segundos que queremos que permanezca nuestra pantalla visible, siendo así necesario indicar este dato al crear una nueva instancia.

El constructor quedar�a así:

public FrmSplash(int segundos)
{
    //
    // Necesario para admitir el dise�ador de Windows Forms
    //

    InitializeComponent();

    timer1.Interval = segundos * 1000;    // pasamos de segundos a milisegundos

    if (!timer1.Enabled)
       timer1.Enabled=true;    // Activamos el Timer si no esta Enabled (Activado)

    //
    // TODO: Agregar c�digo de constructor despu�s de llamar a InitializeComponent
    //
}

Despu�s de esto ya solo nos quedar�a controlar el evento Tick del control Timer, para cerrar el formulario cuando el tiempo indicado se cumpla:

private void timer1_Tick(object sender, System.EventArgs e)
{
    timer1.Stop();     // Se para el timer.
    this.Close();      // Cerramos el formulario.
}

Bueno pues nuestro formulario inicial ya esta finalizado, así que ahora simplemente tendr�amos que llamarlo cuando cargamos el formulario principal (Form1.cs por defecto) de nuestra aplicaci�n, quedando el c�digo como sigue.

private void Form1_Load(object sender, System.EventArgs e)
{
    // -------  Cargamos y mostramos el formulario Splash durante 5 segundos  -----
    FrmSplash f1=new FrmSplash(5);
    f1.ShowDialog(this);     // Mostramos el formulario de forma modal.
    f1.Dispose();
}

El subproceso.

Como esto ya nos funciona, pasemos al tema del subproceso, �Por que un subproceso?, la raz�n es muy simple, para que nuestras aplicaciones sean mas r�pidas (por lo menos ante el usuario), siempre intentamos realizar las operaciones muy costosas en tiempo el menor numero de veces posible, y una buena idea es realizarlas (siempre que sea posible) cuando nuestra aplicaci�n se inicializa, así mejoraremos la respuesta ante el usuario, y este estará mas contento.

Un claro ejemplo de esto es la utilizaci�n de los DataSet, que contienen una representaci�n de nuestros datos en la memoria y trabajan de forma desconectada del soporte de los mismos, (en el caso de la agenda yo cargo todos los datos de la misma en un DataSet al iniciar el programa, pero en un programa de facturaci�n podr�an ser los clientes y art�culos que utilice un usuario, etc.), y para que esos procesos iniciales que pueden tardar cierto tiempo no desesperen al usuario, lo mejor es mostrar nuestro formulario Splash mientras estos se est�n ejecutando, de ahí la idea de crear un subproceso y ejecutarlo mientras el usuario disfruta de nuestro formulario Splash.

En el programa adjunto este subproceso (como ya he indicado antes), realiza la carga de datos en un DataSet, pero para las pruebas yo utilice un simple bucle while, y es este el que utilizare para explicar la implementaci�n del subproceso.

Bueno lo mejor será ir al grano, la mejor soluci�n de las que he probado es (para mi gusto) la mas simple tambi�n, consiste en crear y ejecutar el subproceso al cargar nuestro formulario principal (Form1), y despu�s tal como hac�amos antes mostramos nuestro formulario Splash, quedando el programa tal y como sigue:

using System.Threading;

.
.
.

private void Form1_Load(object sender, System.EventArgs e)
{
    ProcesosInic pInic=new ProcesosInic();
    Thread tAux = new Thread(new ThreadStart(pInic.ProcInic));   // Creamos el subproceso
    tAux.Start();                           // Ejecutamos el subproceso
    while (!tAux.IsAlive);                  // Esperamos a que se este ejecutando

    // -------  Cargamos y mostramos el formulario Splash durante 5 minimo  -----
    FrmSplash f1=new FrmSplash(5,tAux);
    f1.ShowDialog(this);     // Mostramos el formulario de forma modal.
    f1.Dispose();
}

Esta es la clase ProcesosInic que utilice para las pruebas (es muy simple no la comento):

class ProcesosInic
{
    public ProcesosInic()  {}

    public void ProcInic()
    {
        int i=0;

        while (i<1000)
        {
            Console.WriteLine("--- Proceso inicial. Linea: {0} ---",i++);
        }

    }
}

Bueno, pues esto podr�a ser todo, pero el que sea observador se habrá dado cuenta de que la llamada al constructor de nuestro formulario Splash ha cambiado y ahora adem�s del tiempo incluye como argumento nuestro subproceso, �Por que?, muy f�cil nosotros no sabemos de antemano cuanto tiempo tardara en realizarse el proceso, y este puede ser inferior o superior al deseado (es decir el argumento segundos del constructor), pasando a ser ahora un tiempo m�nimo de muestra, si el proceso tarda menos este se mostrara durante los segundos que nosotros le indiquemos, pero si tarda mas el usuario ya estar� cansadito y querr� usar la el programa, por lo tanto lo mejor es esperar el tiempo m�nimo y despu�s cerrar inmediatamente el formulario cuando el subproceso termine, por este motivo he modificado el constructor del formulario Splash y dej�ndolo de la siguiente manera:

using System.Threading;

.
.
.

public class FrmSplash : System.Windows.Forms.Form
{
    .
    .
    .

    private Thread _subProceso;

    public FrmSplash(int segundos, Thread t)
    {
        //
        // Necesario para admitir el dise�ador de Windows Forms
        //

        InitializeComponent();

        timer1.Interval = segundos * 1000;    // pasamos de segundos a milisegundos
        _subProceso=t;

        if (!timer1.Enabled)
           timer1.Enabled=true;    // Activamos el Timer si no esta Enabled (Activado)

        //
        // TODO: Agregar c�digo de constructor despu�s de llamar a InitializeComponent
        //
    }
}

Con la asignaci�n del argumento "t" a nuestra variable privada "_subProceso", podremos acceder a ella desde la clase, y así simplemente con modificar el evento Tick de timer1 de la siguiente manera conseguiremos el efecto deseado.

private void timer1_Tick(object sender, System.EventArgs e)
{
    timer1.Stop();     // Se para el timer.

    if (_subProceso.IsAlive)
    {
        // Una vez transcurrido el tiempo inicialmente establecido
        // establezco un intervalo de un segundo para mirar si el proceso a terminado.

        if (timer1.Interval!=1000)
            timer1.Interval=1000;

        timer1.Start();
    }
    else
        this.Close();      // Cerramos el formulario.
}

Esto es todo lo que da de si la primera parte del articulo, que aunque parece mucho rollo si se mira el c�digo fuente del ejemplo se ve que es algo muy sencillo.

Desarrollo de una agenda aplicando la programaci�n en tres capas (Interfaz de usuario, Capa de negocios, Capa de acceso a datos).

Como he indicado al principio y llegados hasta este punto quise realizar algo mas, ya que un simple formulario que llama a otro y ejecuta un bucle, queda un poco pobre, así que pensé que se pod�a hacer con el formulario principal de la aplicaci�n, y lo que se me ocurrió en el momento es realizar una agenda, y de hacerlo, hacerlo bien es decir realizar la programaci�n en tres capas para que la persona que quiera ver un ejemplo tenga a mano algo sencillo.

La capa de acceso a datos.

Aquí es donde se me plantea la primera duda, y no es otra que utilizar, SQL Server o MSDE, un fichero de Access, un fichero plano, etc., pero al pensar en ello lo que mejor me pareció es utilizar un fichero XML, ya que no necesita de otro programa, y se puede cargar sin problemas en un DataSet.

Esta capa solo tiene una clase, que llamo FichAgenda, que contendrá los datos en un DataSet, y adem�s proporcionara la funcionalidad b�sica, de cargar, borrar, modificar, crear y guardar los datos de la agenda, (la persona que este interesada, puede probar a modificarla, para que utilice SQL Server o ACCESS, etc.), como en si es muy simple, solamente realizo un comentario sobre el m�todo est�tico "CargarDatos", que tiene un control de errores sobre la lectura del fichero que no realiza nada en caso de producirse el error, y realmente esto de no realizar nada tiene una raz�n, ya que el error mas probable es que no exista el fichero, pero al tener en la clase el DataSet, perfectamente construido (sin datos claro) y si no queremos grabar nada, no necesitamos crear el fichero en el disco duro, y si queremos grabar algo, al llamar al m�todo "GuardarDatos" este será creado.

public static void CargarDatos()
{
    _ds=new DataSet();               // Creamos una nueva instancia de un DataSet
    _ds.Tables.Add(Estructura());    // Le A�adimos la estructura

    try (_subProceso.IsAlive)
    {
        _ds.ReadXml("datos.xml");     // Leemos los datos del fichero datos.xml
    }
    catch
    {
        Console.WriteLine("Error al leer el fichero de datos.")
    }
    _dtCargados=true;
}

La capa de negocios.

Esta capa solo tiene una clase Persona, ya que no quer�a que fuera mas extenso, por dejarlo muy simple (Es un peque�o ejemplo), y como me parece tan simple recomiendo consultar el c�digo.

El interfaz de usuario.

El interfaz de usuario es el formulario principal de la aplicaci�n, (como buen ejercicio se podr�a realizar otro utilizando Web Forms en vez de utilizar Windows Forms), como explicaci�n lo mejor que se puede hacer ver directamente el c�digo de la aplicaci�n.

Bueno, pues por fin esto si es todo, espero que todo este bien, ya que es mi primer articulo, y me gustar�a que fuera �til, solo a�adir que en caso de quejas, dudas, etc. se pueden poner en contacto conmigo en el correo indicado, un saludo a todos.



ir al índice

Fichero con el c�digo de ejemplo: ACUESTA_FormularioSplash.zip - Tama�o 96,4 KB

Índice de la sección dedicada a punto NET (en el Guille)