Interfaces Avanzadas
[Formas con diseño avanzado]

Fecha: 13/May/2005 (04-Mayo-2005)
Autor: Ewing Morales (ewingmarx@yahoo.com)

 


Muchas veces hemos tenido la necesidad o la curiosidad impactar a la gente a la que van dirigidas nuestras aplicaciones, y muchos no solo ponen énfasis en la funcionalidad de la aplicación sino además en como luce la misma. A nosotros mismo nos agrada mas trabajar con interfaces no solo funcionales sino además agradables a la vista.

Desafortunadamente Windows tiene sus limitaciones y nosotros como desarrolladores tenemos que aprender a trabajar con ellas y tratar de solventar estas con un poco de imaginación.

Intentaré (en una serie de colaboraciones) mostrar como poder elaborar interfaces de aplicaciones que impacten no solo a los neófitos sino también a los doctos, en espera que el camino que yo ya recorrí en mi aprendizaje de VB.Net y k.o. le sirva a los demás para lograr de manera más rápida y sencilla su objetivo.

En términos generales van a haber dos entregas:

  • La primera les mostrara como hacer que las aplicaciones se vean como uno quiere y no como Windows puede.

  • La segunda mostrara como hacer un botón realmente personalizado por medio de una imagen.


  • [Primera Parte] Formularios con diseño avanzado

    Antes de seguir hablando dejen mostrarles lo que pueden lograr con el código que les estoy compartiendo:


    Como pueden ver, el formulario tiene formas suaves (no aserradas), sombras y semitransparencias (entre otras cosas).

    Como se logro esto, bueno, no es mas que un conjunto de trucos, pero eso si, muy buenos y que no solo les pueden servir para esto sino para mas cosas que deseen hacer.

    El truco consiste en copiar la imagen que se encuentra detrás de nuestro formulario, pintarla en un lienzo (Rectangle) nuevo y después pintar sobre el mismo lienzo la imagen PNG (mezcla de imágenes). Esto permitirá que se respeten todas las características de la imagen que se definieron en el editor gráfico.

    Descripción de componentes

    1) Antes que nada necesitamos un buen diseño grafico, yo diseño con photoshop (de cuya introducción saque la idea del formulario), pero pueden utilizar cualquier otra aplicación que les permita guardar PNGs (en el código va el png que utilizo).

    2) Necesitan un formulario con las mismas medidas que la imagen PNG (en realidad eso no es necesario pero para casos de aprender, háganlo así). Definan su propiedad FormBorderStyle como None y asignen a BackgroundImage el png que crearon.

    3) Agreguen un control de tipo Panel, pónganle como nombre LTitulo, hagan que sea transparente y ubíquenlo sobre la porción de imagen que deseen que sea su barra de control que les permita arrastrar la ventana del formulario.

    4) Creen ahora un botón (por ahora trabajaremos con los normales y feos) que se llame Cerrar para que cuando le demos Click se cierre el formulario.

    Hasta ahora no hemos visto nada de código pero a continuación mostramos que se puede hacer con el panel LTitulo y el botón Cerrar.

    #region "Codigo para Drag Form"
    // ==========================================================================
    
    private Boolean arrastrar;
    private Point pointMD;
    private Point pointFM;
    private int xDelta, yDelta;
    private Boolean activo;
    
    private void LTitulo_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        arrastrar = true;
        pointMD = MousePosition;
        pointFM = this.Location;
        xDelta = pointMD.X - pointFM.X;
        yDelta = pointMD.Y - pointFM.Y;
    
        this.Opacity = 0.20;
        MuestraImagen(true);
    }
    
    private void LTitulo_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        Point pointNP = new Point();
        if (arrastrar) 
        {
            pointNP.X = MousePosition.X - xDelta;
            pointNP.Y = MousePosition.Y - yDelta;
            this.Location = pointNP;
        }
    }
    
    private void LTitulo_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        arrastrar = false;
        MuestraImagen(false);
    }
    
    private void Cerrar_Click(object sender, System.EventArgs e)
    {
        this.Close();
    }
    
    // ==========================================================================
    #endregion

    Vemos en el código los eventos Down, Up y Move del ratón para nuestro panel LTitulo, por lo tanto debemos hacer la correspondiente asociación eventos - funciones para que pueda funcionar, así mismo para el evento Click del botón Cerrar que definimos. La manera más rápida de hacer esto es desde el panel de propiedades de la interfaz de desarrollo como se muestra a continuación (fíjense en los iconos que tengo seleccionados de este panel para poder hacerlo):

    5) Necesitamos inicializar algunas variables antes de que pueda funcionar todo en conjunto, esto lo haremos en el evento Load del formulario, además agregaremos un comportamiento específico del formulario cuando este se encuentre activo (Activated) y cuando este no sea la ventana que tiene el foco en Windows (Deactivate). Pero sobre todo, necesitamos nuestra función que se llama MuestraImagen que nos permite hacer el copiado de lo que se haya detrás de nuestro formulario. Acá el código:

    #region "Variables de Control Grafico"
    private Image img;
    private Image result;
    private Rectangle rectangle;
    #endregion
    
    #region "Funciones de Actualizado de Formulario"
    private void MainForm_Load(object sender, System.EventArgs e)
    {
        // Inicializacion de variables
        img = this.BackgroundImage;
        result = new System.Drawing.Bitmap(img.Width, img.Height);
        rectangle = new System.Drawing.Rectangle(0,0,img.Width,img.Height);
        MuestraImagen(false);
        activo = true;
    }
    
    private void MainForm_Activated(object sender, System.EventArgs e)
    {
        if (activo == false)
        {
            MuestraImagen(false);
            activo = true;
        }
    }
    
    private void MainForm_Deactivate(object sender, System.EventArgs e)
    {
        this.Opacity = 0.50;
        activo = false;
    }
    
    private void MuestraImagen(Boolean mueveForma)
    {
        System.Drawing.Graphics
        graphics = System.Drawing.Graphics.FromImage(result);
    
        if (mueveForma)
        {
            graphics.Clear(Color.White);
        }
        else
        {
            CapturaForm.Control(this);
            graphics.DrawImage(this.BackgroundImage,
            rectangle,
            0, 0, img.Width, img.Height,
            System.Drawing.GraphicsUnit.Pixel);
        }
        graphics.DrawImage(img,
        rectangle,
        0, 0, img.Width, img.Height,
        System.Drawing.GraphicsUnit.Pixel);
    
        graphics.Dispose();
    
        this.BackgroundImage = result;
        this.Refresh();
    }
    #endregion

    Acuérdense de asociar los eventos Load, Activated y Deactivate del formulario a las funciones correspondientes que aparecen en el código anterior.

    6) Como les decía en un principio, la función MuestraImagen lo que hace primero es obtener un nuevo fondo a través del método Control de la clase CapturaForm que aun no hemos visto. Si el formulario esta por moverse las imágenes a mezclar (dibujar una sobre otra) son un fondo blanco y nuestro PNG, además se cambia la opacidad de la forma a un 20% (vean LTitulo_MouseDown, que es la única vez que se envía true como parámetro a la función). Cuando uno cambia a otra ventana de Windows, el formulario se vuelve transparente a un 50% (vean MainForm_Deactivate). Cuando uno deja de arrastrar el formulario se efectúa el siguiente proceso: se oculta por un momento el formulario, se copia el fondo, se dibuja el fondo en nuestro lienzo temporal (rectangle), se encima la imagen PNG en el lienzo, se cambia el fondo del form por el nuevo lienzo, se refresca la imagen del form aun estando oculto a la vista y por ultimo se hace visible el form.

    Todo lo anterior es apenas perceptible por el usuario aunque si existe un pequeño parpadeo, pero bueno, hay que pagar algunas cosas por disfrutar de una interfaz así... ¿no creen?

    La siguiente imagen les puede dar una idea de como se vería el formulario al arrastrarlo (y es cuando nuestro truco queda un rato al descubierto).

    7) Por ultimo, necesitas las funciones y agregados para poder realizar las capturas de pantalla. Yo encontré estas funciones en la red y es software libre (PSDLA: en el código viene una breve descripción de los términos) publicado por Excellence Foundation (Don@xfnd.org). Las funciones originales permiten otros tipos de capturas, pero especialmente la adecuación que yo hice nos sirve para estos fines en específico, ni más ni menos. Estas librerías están definidas bajo los namespaces Captura y Dll y se encuentran en el propio código principal, para que no batallen con dlls externas. Las puse bajo un grupo región a cada una para que en tu código solo las veas de la siguiente manera:

    + "NameSpace Captura"
    + "NameSpace DLL"

    ¿Puedes ver el código? ¿Puedes modificarlo? Por supuesto que si. Simplemente no me meto a explicarlo porque es mejor que los veamos como auxiliares y no como el núcleo de la aplicación.

    También es importante que su definición vaya hasta lo último del código ya que al parecer existe un bug en el Visual Studio tal que si lo pones al principio, empiezas a tener problemas con las imágenes que utilices en tus controles. ¿Por qué? No tengo idea pero al menos pasa aquí en mi maquina. De cualquier manera pónganlos al final.

    Personalicen

    Pueden personalizar sus formularios, agregando mas PNGs, solo recuerden que deben ponerlos como imágenes de fondo de objetos tipo Panel. Los objetos como Label o PictureBox tienen sus propias deficiencias que no permiten explotar al máximo una aplicación gráfica como esta que queremos implementar. En mi caso la idea es hacer un informador del clima, el cual me mostrará el clima actual y su pronóstico. Por entendido se da que la información vendrá lo mas gráfico que se pueda (vean el informador del clima del Dashboard de Apple OSX).

    La aplicación que les envío se debe ver hasta ahora así:

    Aún habrá más

    Acuérdense que en la siguiente entrega verán como hacer un control botón que aparte de ser impactante responde únicamente cuando estas realmente dentro de el y no solo dentro del cuadro que lo define. El botón puede ser de cualquier forma y con esto podrían completar este ejemplo de la siguiente manera.

    Pero eso será hasta la próxima entrega.


    Espacios de nombres usados en el código de este artículo:

    System.Runtime.InteropServices


    Fichero con el código de ejemplo: ewing_interfaz_avanzada.zip - 120 KB


    ir al índice