Combo para seleccionar colores (Winforms + C#)

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!

3 comentarios sobre “Combo para seleccionar colores (Winforms + C#)”

  1. «Pues, ya verás que fácil… apenas cinco líneas de código, y será tuya…» jajaja parece que estuvieras ofreciedo algo a la venta, jajaja wena!! :P, pero muy buen aporte, se agradece, se puede descargar? :O, spero que si..

    thanks!!

  2. @Ricardo

    Gracias por tus comentarios… jejeee… bueno, si me salió la vena comercial, pero ya se sabe que con la crisis… se debe vender lo que sea 😛

    El código está todo en el post, no necesitas «descargarte» nada… Si quieres probarlo y tienes alguna duda, enviame un mail y te ayudo en lo que sea 🙂

    Saludos!!! 😉

  3. Hola Eduard, muy interesante tu post, pero tengo una consulta, como haría para poder darle un color al Formulario en base a lo que eliga del ComboBox? :-/, he intentado y no me sale, he estado haciendo lo siguiente en el evento:
    SelectedIndexChanged,

    this.BackColor = this.cmbColor1.BackColor;

    Luego intente:

    string color = this.cmbColor1.SelectedItem.ToString();
    this.BackColor = Color.FromName(color);

    Pero tampoco me sale 🙁 espero puedas ayudarme… si??

    Gracias!! 😀

    Milagros Rojas Pereyra

Responder a etomas Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *