Combo para seleccionar colores (Winforms + C#)

 ·  ☕ 4 min  ·  ✍️ eiximenis

    Nota: Este post ha sido importado de mi blog de geeks.ms. Es posible que algo no se vea del todo "correctamente". En cualquier caso puedes acceder a la versión original aquí

    Hola… qué tal?

    Imagina que en algún proyecto que estés haciendo, quieres ofrecer una combo para seleccionar colores. De acuerdo, ya se que hay otros métodos para hacer que el usuario seleccione un color, como usar el ColorDialog, pero a lo mejor te interesa que el usuario sólo pueda escoger colores de una lista predeterminada…

    Por suerte en .NET hacer que una combo dibuje sus elementos como nosotros queremos, es realmente simple… ¿quieres tener una combo como esta?

    image

    Pues, ya verás que fácil… apenas cinco líneas de código, y será tuya…

    Paso 1: Añadir la combo al formulario

    Añade una ComboBox normal a tu proyecto, y establece las propiedades DropDownStyle a DropDownList (para que el usuario no pueda teclear valores nuevos) y DrawMode a OwnerDrawFixed.

    La propiedad DrawMode es la clave: Puede tener tres valores, que son “Normal” (el sistema operativo se encarga de dibujar la combo), “OwnerDrawFixed” (nosotros nos encargamos de dibujar cada elemento) y “OwnerDrawVariable” (nosotros nos encargamos de dibujar cada elemento y además cada elemento puede tener un tamaño distinto).

    Paso 2: Código para dibujar cada elemento

    Crea una función gestora para el evento DrawItem: la combo lanza este evento cada vez que debe dibujar un elemento. La función gestora recibe un objeto DrawItemEventArgs que contiene toda la información que necesitamos para poder “dibujar” el elemento: de que elemento se trata, el contexto gráfico a usar y las coordenadas que ocupa el rectángulo del elemento dentro del contexto gráfico de la combo…

    Las primeras líneas de la función gestora serían las siguientes:

    ComboBox cmb = sender as ComboBox;
    if (cmb == null) return;
    if (e.Index < 0) return;
    if (!(cmb.Items[e.Index] is Color)) return;
    Color color = (Color)cmb.Items[e.Index];

    Aquí simplemente estamos asegurándonos de que el elemento que vamos a dibujar sea un objeto Color. Para ello accedemos a la propiedad Index del objeto DrawItemEventArgs que recibimos que nos indica el índice del elemento que estamos dibujando.

    Ahora solo nos queda dibujar el elemento: un rectángulo con los bordes negros y rellenado del color indicado, junto al nombre del color:

    Brush brush = new SolidBrush(color);
    e.Graphics.DrawRectangle(
    Pens.Black,
    new Rectangle(e.Bounds.Left + 2, e.Bounds.Top + 2, 19,
    e.Bounds.Size.Height - 4));
    e.Graphics.FillRectangle(brush,
    new Rectangle(e.Bounds.Left + 3, e.Bounds.Top + 3, 18,
    e.Bounds.Size.Height - 5));
    e.Graphics.DrawString(color.Name, cmb.Font,
    Brushes.Black, e.Bounds.Left + 25, e.Bounds.Top + 2);
    brush.Dispose();

    El primer DrawRectangle dibuja el borde del rectángulo, el FillRectangle pinta su interior y el DrawString escribe el nombre del color. Finalmente recordad que debemos hacer dispose de cualquier objeto GDI+ que usemos.

    Como se puede observar, apenas cinco líneas de codigo GDI+.

    Paso 3: Perfeccionando el tema…

    La combo ya es 100% funcional, pero si la usais vereis que “no resalta” en azul el elemento seleccionado, tal y como hace por defecto la combobox… Evidentemente no lo hace porque no hemos puesto código para ello, pero tranquilos: son apenas tres líneas de código.

    El propio objeto DrawItemEventArgs tiene todo lo que necesitamos para poder hacerlo:

    1. El método DrawBackground() que dibuja el fondo del elemento actual: en blanco en azul en función de si tiene el cursor del ratón encima o no.
    2. La propiedad ForeColor que nos devuelve el color con el que dibujar el elemento actual (por defecto es negro si no tiene el cursor del ratón encima o blanco en caso contrario).
    3. La propiedad BackColor que nos devuelve el color que se usa en el método DrawBackground.

    El código final para dibujar nuestra combo es el siguiente:

    private void cmbColor_DrawItem(object sender, 
    DrawItemEventArgs e)
    {
    ComboBox cmb = sender as ComboBox;
    if (cmb == null) return;
    if (e.Index < 0) return;
    if (!(cmb.Items[e.Index] is Color)) return;
    Color color = (Color)cmb.Items[e.Index];
    // Dibujamos el fondo
    e.DrawBackground();
    // Creamos los objetos GDI+
    Brush brush = new SolidBrush(color);
    Pen forePen = new Pen(e.ForeColor);
    Brush foreBrush = new SolidBrush(e.ForeColor);
    // Dibujamos el borde del rectángulo
    e.Graphics.DrawRectangle(
    forePen,
    new Rectangle(e.Bounds.Left + 2, e.Bounds.Top + 2, 19,
    e.Bounds.Size.Height - 4));
    // Rellenamos el rectángulo con el Color seleccionado
    // en la combo
    e.Graphics.FillRectangle(brush,
    new Rectangle(e.Bounds.Left + 3, e.Bounds.Top + 3, 18,
    e.Bounds.Size.Height - 5));
    // Dibujamos el nombre del color
    e.Graphics.DrawString(color.Name, cmb.Font,
    foreBrush, e.Bounds.Left + 25, e.Bounds.Top + 2);
    // Eliminamos objetos GDI+
    brush.Dispose();
    forePen.Dispose();
    foreBrush.Dispose();
    }

    Y listos!! Nuestra combo ya está lista para usar. Podeis meterle algunos colores para probar:

    cmbColor1.Items.Add(Color.Black);
    cmbColor1.Items.Add(Color.Blue);
    cmbColor1.Items.Add(Color.Red);
    cmbColor1.Items.Add(Color.White);
    cmbColor1.Items.Add(Color.Pink);
    cmbColor1.Items.Add(Color.Green);

    Y este es el resultado final:

    image

    ¿No está nada mal, eh?

    Saludos a todos!

    Si quieres, puedes invitarme a un café xD

    eiximenis
    ESCRITO POR
    eiximenis
    Compulsive Developer