Chapter 6. Cómo hacer que el widget generado por el diseñador funcione

Como ya habrá notado, el widget se muestra pero no hace nada, así que le haremos trabajar un poco.

Añadir nombres, slots y conexiones

En primer lugar, abra con el diseñador el archivo centralviewbase.ui, utilizando la pestaña Grupos de archivos (a la izquierda), dentro del bloque Interfaz de usuario.

Dentro del diseñador, seleccione cada uno de los widgets que se utilizarán desde la aplicación, y deles un nombre. Yo he llamado m_label al elemento gráfico, m_red al deslizador del componente rojo, y m_green y m_blue a los otros dos, respectivamente. En caso de que usted no esté familiarizado con el sistema de nomenclatura m_nombre, puedo decirle que este sistema es el mejor invento desde el pan. Hace que el código sea mucho más sencillo de leer y mucho más comprensible por otros desarrolladores.

A modo de normas generales del esquema de nomenclatura que utilizo, cito algunas reglas:

  1. Siempre se nombra a los componentes en la forma “maximumSize”, y no como “MaximumSize” o “maximum_size”. La única excepción es en los nombres de las clases, que deben empezar por mayúscula (“MaximumSize”).

  2. Siempre se coloca "m_" como prefijo de los nombres de las variables miembro. De esta forma siempre se sabe si una variable es local a un método o si depende de clase en la que se encuentra.

  3. No utilice nunca getXXX() como nombre para acceder a un método de una clase (lo métodos normales que únicamente hacen { return m_XXX; };). Es mucho mejor utilizar siempre el nombre de la propiedad, algo como QFont font() const { return m_font; };. De esta forma, el método set correspondiente, debería ir precedido por “set”, de forma que la pareja get/set de una propiedad quede en la forma font() y setFont(const QFont &) en nuestro ejemplo.

  4. Las variables booleanas deben tener siempre nombres positivos, en vez de cosas como bool m_noBackground. Es mucho más fácil entender el uso de la variable si se llama m_background y después utilizar if (m_background) ... en vez de if (!m_noBackground) ....

Bien, ahora nuestro widget tiene nombres que podremos utilizar en la implementación de CentralView (ya que CentralView hereda de CentralViewBase), pero aún no es suficiente. También debemos añadir slots a CentralViewBase, y, como son métodos virtuales, los sobrecargaremos en CentralView. Vamos a hacerlo para que lo entienda mejor.

En primer lugar, abra el diálogo Slots del menú Edit o pulsando el botón derecho del ratón en el widget principal. Pinche en New Function y dele el nombre setRed(int v), cree otros dos slots llamados setGreen(int v) y setBlue(int v). Haremos que se llame a estos slots cada vez que el usuario modifique los deslizadores rojo, verde o azul. Para hacerlo, salga del diálogo y selecione Connect Signals/Slots en el menú Tools, en el icono de la flecha de la barra de herramientas, o pulsando F3. Después pinche con el botón izquierdo del ratón sobre el deslizador rojo y, sin soltarlo, muévalo hacia el widget principal (por ejemplo hacia uno de los bordes). Hay un rectángulo magenta que muestra los widgets que serán conectados. Una vez que se ha determinado el deslizador rojo como origen y el widget principal como destino, suelte el botón y se le mostrará un diálogo en el que configurar qué señal del elemento de origen se conectará con qué slot del widget de destino.

En el diálogo, pinche en el campo No Signal y seleccione la señal valueChanged(int). Después, seleccione el slot setRed(int). Conecte también las señales correspondientes de m_green y m_blue con setGreen(int) y setBlue(int).

Edición de conexiones en el diseñador

Ahora, conviene recordar que los componentes de color van normalmente de 0 a 255 (y eso es lo que dice la documentación de QColor), así que lo propio sería que el deslizador nos proporcionase valores entre 0 y 255. Para hacerlo, seleccionamos cada deslizador y fijamos su propiedad maxValue (en el editor de propiedades) a 255.

Guarde el interfaz de usuario y cierre el diseñador para volver a KDevelop.

Implementación de los slots

De vuelta en KDevelop, abra la pestaña Clases, pinche con el botón derecho sobre la clase CentralView y seleccione Nuevo método en el menú emergente. Aquí vamos a reimplementar setRed, de forma que se utilice este en vez del que aparece en CentralViewBase. Así que el nombre es setRed, el tipo es void (hace referencia al tipo del valor devuelto), y le incluimos un parámetro de tipo int, para hacerlo coincidir con el slot que hemos creado en el diseñador. Tendremos que realizar la misma operación otras dos veces, para crear los slots de setGreen y setBlue.

Añadir un slot a CentralView con KDevelop

Ahora vamos a añadir una nueva variable, que será el color utilizado en TheTinter, y que tendrá tipo QColor. Para hacerlo, pinche nuevamente con el botón derecho en el nombre de la clase en la vista de árbol y seleccione Añadir atributo. Utilice como tipo QColor y como nombre m_color. Para ser correctos, también la haremos protegida.

Añadir un atributo a CentralView con KDevelop

Ahora vamos a implementar los slots que acabamos de añadir para modificar el valor de m_color. Utilizaremos el siguiente código:

void CentralView::setRed(int v)
{
     m_color.setRgb( v, m_color.green(), m_color.blue() );
     updatePixmap();
}
que utiliza el nuevo valor del componente rojo y deja los otros dos sin cambios. También llamamos al método updatePixmap() que actualizará el mapa de pixels con el color m_color. Ahora vamos a añadir el método y a implementarlo.

void CentralView::updatePixmap()
{
    QPixmap pixmap(128,128);
    pixmap.fill(m_color);
    m_label->setPixmap(pixmap);
}
La primera línea crea un mapa de pixels de 128x128, y en la segunda línea se rellena del color. La tercera línea coloca el mapa de pixels en el elemento de imagen. El tamaño 128x128 es un tanto arbitrario, ya que el elemento gráfico lo redimensionará para que llene todo el área (puede cambiar esto, si lo desea, en las propiedades).

Este es nuestro código fuente para s3, pronto haremos que cargue una imagen y la tiña con el color, en vez de que únicamente aparezca este rellenando un rectángulo, pero, antes, trataremos de hacer que no parpadee (fíjese en que si mueve los deslizadores muy rápido, se produce mucho parpadeo). Ese será nuestro siguiente objetivo.