¡Al grano con Nokia Qt!


Table of Contents

1. Introducción
2. Antes de mirar esta guía
3. Mi primer programa Qt de verdad
3.1. Definiendo una ventana de diálogo
3.2. El programa para usar el diálogo
3.3. El archivo de proyecto (.pro)
3.4. Obteniendo el ejecutable "a pelo"
4. La colección de ventanucos
5. Me pierdo. ¡Ayuda!
6. Y ahora con Qt Creator
7. Dando vida: señales y ranuras (signal y slot)
7.1. La idea
7.2. Conectando cosas de nuestra ventana
7.3. Mi propio "slot"
7.4. Mi propia "signal"
7.5. Probando: estornudos y microbios
8. Diseñando ventanas con el ratón
8.1. El planteamiento
8.2. El formulario con Qt Designer
8.3. Pasándole la moto al formulario con uic
8.4. Creando una clase para contener el formulario
8.5. Usando el nuevo diálogo
9. ¿Hasta dónde puedo llegar con Qt?
10. ¿Y ahora qué?
11. Y para crear rapidito los proyecto de DSII
12. Descargas
13. Preguntas frecuentes
14. Bibliografía y enlaces

Última revisión: 3 de noviembre de 2011.

Pendents:

-preparar enllaços secció "Antes de mirar ..."

(descargar versión PDF (no actualizado))

1. Introducción

Posiblemente, Qt es el mejor conjunto de herramientas para el desarrollo de aplicaciones multiplataforma en C++.

Aunque empezó como herramienta para el diseño de la interfaz gráfica de usuario (GUI), su evolución va mucho más allá, permitiendo la aplicación de las tecnologías más productivas y aceptadas (SQL, XML, SVG, OpenGL, WebKit, multi-hilo, etc.) de una manera sencilla e intuitiva.

Es, por tanto, un buen candidato para poder desarrollar aplicaciones de cualquier naturaleza con "moderada" sencillez. Sobretodo para los que no son expertos programadores.

Respecto a introducirse en su uso ... libros hay varios (ver bibliografía), pero quizá se pueda simplificar su aprendizaje si se evitan rodeos y enfoques inadecuados que se ven en algunos libros y tutoriales.

El propósito de este tema/tutorial es intentar transmitir la filosofía correcta sobre Qt/C++ de una manera lo más inmediata y limpia posible. Y, sobretodo, enfocarla a las características propias de nuestros alumnos.

Esto no es un sustituto de un buen libro de Qt. Es una inmersión a pulmón libre en Qt a nuestro estilo. Al mismo tiempo, se recomienda ir usando el excelente libro de Molkentin.

2. Antes de mirar esta guía

Antes de meterse en Qt y en esta guía, es recomendable que se tengan claros los siguientes puntos:

3. Mi primer programa Qt de verdad

3.1. Definiendo una ventana de diálogo

Se va a empezar por crear una ventana de diálogo. En la sección "La colección de ventanucos" se puede ver el aspecto de la ventana que se pretende crear.

Para ello se propone crear una clase C++ que derivará de otras clases que proporciona Qt. No importa si no se comprenden ahora los significados de los nombres de las clases.

Como siempre en C++, primero hay que definir la clase. Ésta es la que se propone:

// Fichero: tventanuco.h
// Primer programa Qt para DSII 2010/2011

#ifndef TVENTANUCO_H
#define TVENTANUCO_H

// elementos que voy a necesitar
#include <QDialog>  // voy a crear un dilogo!
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>

// definicin de la nueva clase TVentanuco que vamos
// a derivar de QDialog
class TVentanuco : public QDialog
{
    Q_OBJECT    // <-- ponlo siempre que quieras que funcione signal/slot

public:
    TVentanuco(const char *mensaje);   // el constructor

private:
    // vamos a meter unas cuantas cosas
    double valor;
    QVBoxLayout *lyDistribuidor;
    QLabel *lbEtiqueta;
    QLineEdit *leEdicion;
    QPushButton *btToquetear;
    QPushButton *btCerrar;
};

#endif // TVENTANUCO_H

Esta nueva clase TVentanuco va a ser una derivación de la clase QDialog de Qt que permite la construcción de ventanas de diálogo.

Si se mira el manual de Qt, se verá que se hubiese podido derivar de otras cosa, por ejemplo, un QWidget, un QMainWindow, un QSplash, etc.

En la línea 8 se tiene una inclusión de la cabecera QDialog (sin el .h) que es necesaria, pues se va a derivar de QDialog. En Qt, para simplificar el tener que recordar nombres de cosas, las cabeceras y los tipos de clase tiene el mismo nombre. Así, si se necesita un QPushButton, simplemente se tendrá que hacer #include <QPushButton> en el archivo que lo declare o implemente.

Destacar en la línea 18 la inclusión de la etiqueta especial Q_OBJECT. De momento, supongase que hay que ponerla siempre.

En la zona privada del objeto, entre las líneas 26-30, se declaran varios punteros a clases de Qt. En el manual de Qt se puede mirar para qué sirven.

Ahora se pasa a la implementación. Se propone el siguiente listado:

// Fichero: tventanuco.cpp
// Primer programa Qt. DSII curso 2010/2011
#include "tventanuco.h"

// Hay que meter la cabecera de los objetos Qt que vayas a usar
// No hace falta si ya están en la cabecera
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>

TVentanuco::TVentanuco(const char *mensaje)
    :QDialog()  // llamamos al constructor de la base
{
    // enviamos el mensaje al titulo del dialog
    setWindowTitle(mensaje);

    //crear el distribuidor de objetos
    lyDistribuidor = new QVBoxLayout(this);

    // creamos una etiqueta y la metemos en el "layout"
    lbEtiqueta = new QLabel(tr("A ver si esto va o no"));
    lyDistribuidor->addWidget(lbEtiqueta);

    // parar jugar con los "layout", meto un "muelle"
    lyDistribuidor->addStretch();

    // ahora una linea de edicin
    leEdicion = new QLineEdit;
    lyDistribuidor->addWidget(leEdicion);

    // ahora un boton
    btToquetear = new QPushButton(tr("Tocar narices"));
    lyDistribuidor->addWidget(btToquetear);

    // ahora el boton de cerrar
    btCerrar = new QPushButton(tr("Salir"));
    lyDistribuidor->addWidget(btCerrar);
}

Lo primero es incluir la cabecera de las clases de Qt que necesitemos que no estén ya en la cabecera de TVentanuco. En este ejemplo se podrían eliminar las que se han puesto.

Lo único que se ha implementado es el constructor, que es bastante intuitivo. Simplemente se van creando dinámicamente los objetos y se van introduciendo en el distribuidor (Layout).

Observar que todos los textos que vayan a salir en pantalla van dentro de la función tr() (en realidad QObject::tr()) que, a partir de ahora, se recomienda usar, pues sirve para facilitar el desarrollo de versiones multilingues. Se puede eliminar tr() sin problema.

3.2. El programa para usar el diálogo

A continuación tenemos un programa principal muy sencillo para poder usar el diálogo antes propuesto.

// Fichero: main.cpp
// Probando el TVentanuco desde la linea de ordenes de Windows. DSII 2009/2010

#include <QApplication>
#include "tventanuco.h"

int main(int argc, char *argv[]) {
        QApplication app(argc, argv);
        int resultado;

        // un ventanuco creado dinamicamente
        TVentanuco *vent1;
        vent1 = new TVentanuco("(vent1) Estooo, probando ventanuco");
        vent1->show();

        // un ventanuco creado estaticamente como variable automatica
        TVentanuco vent2("(vent2) Y ahora otro ventanuco");
        vent2.show();

        // cuando termine la aplicacion, no se habra hecho "delete" de vent1,
        // pero si que se habra llamado automaticamente al destructor de vent2.
        // recordadme que os explique lo que pasa

        resultado = app.exec(); // a funcionar! empieza el bucle de eventos.

        return(resultado);
 }

Como se quiere hacer una aplicación gráfica Qt, lo primero es crear una instancia de la clase QApplication.

En la línea 8 se crea app, que es esa instancia, y a la que se le pasan los argumentos argc y agrv que el S.O. le pasa a la aplicación. Esto permite, por ejemplo, que se pueda configurar la apariencia de nuestro programa.

Destacar que la construcción de app se hace usando variables automáticas. El beneficio de hacerlo así es que, al terminar el programa, C++ llamará automáticamente al destructor de app.

De la línea 12 a la 18 se crean un par de objetos de la clase TVentanuco y se llama al método publico show().

Finalmente, se llama al método exec() de QApplication para pasar el control al bucle de eventos Qt. En este punto el programa se quede a la espera de que usemos normalmente los diálogos.

3.3. El archivo de proyecto (.pro)

Se tienen ya todas las piezas de código C/C++ para poder construir la aplicación. El siguiente paso es proporcionar a Qt un archivo con información de qué se quiere hacer con esas piezas.

El siguiente listado es un típico archivo de proyecto Qt para dar dicha información:

#Fichero: qt_per_tots.pro
#Configuración del proyecto para el primer ejemplo de DSII. Curso 2009/2010

#indicar que tipo de destino se quiere compilar. En este caso una aplicacción
TEMPLATES = app

#con += añades y con -= quitas

#indicar la lista de módulos cpp que forman la aplicación
SOURCES += tventanuco.cpp
SOURCES += main.cpp

#indicar la lista de cabeceras propias que se van a usar
HEADERS += tventanuco.h

La sintaxis de este archivo es parecida a un archivo de guión de Bourne shell para Unix. En este ejemplo básico, se establece el valor de ciertas variables que, en este caso, son:

  • TEMPLATES: Para indicar que tipo de salida queremos: un programa, una biblioteca, etc. En este caso, app significa que queremos un programa ejecutable.

  • SOURCES: Para indicar la lista de los módulos C/C++ que forman mi aplicación.

  • HEADERS: Para indicar los archivos de cabecera "míos" que son parte de la aplicación.

Y ya está todo. Así de fácil ¿no?.

3.4. Obteniendo el ejecutable "a pelo"

Ahora vamos a obtener el ejecutable.

Los entornos de desarrollo integrados (IDE) son muy monos y útilies, pero muchísimas veces no se sabe lo que se está haciendo.

El propósito de este apartado es entender ver que es lo que está ocurriendo por debajo del IDE que se usará más adelante y, así, comprender mejor la filosofía Qt. Para ello se va utilizar la línea de órdenes de Microsoft Windows (probado en XP, Vista y 7).

Para abrir una consola de Windows correctamente configurada, haremos: Inicio->Programas->Qt SDK ... -> Qt Command prompt.

La siguiente imagen muestra la consola abierta.

Figure 1. Entrando a la consola de Windows

Entrando a la consola de Windows

Antes de continuar, se deberán meter todos los archivos anteriores en un directorio que creemos, por ejemplo, en el escritorio de Windows.

A continuación se deberá ir a dicho directorio usando la orden cd de Windows. Con la orden dir se puede ver la lista de archivos que hay en el directorio.

C:\...> cd “\Documents and Settings\(usuario)\Escritorio\(carpeta)”
C:\...> dir

Una vez en el directorio destino, se usará la orden de Qt qmake con el nombre del archivo de proyecto como argumento.

C:\...> qmake qt_per_a_tots.pro

La orden qmake procesa el archivo de proyecto y genera los archivos de guión de C/C++ (makefiles) y directorios necesarios para compilar el proyecto con el compilador de C/C++ configurado por el entorno.

[Important]Important

Recuérdese que Qt es un conjunto de herramientas para desarrollo de aplicaciones en C/C++, pero no es un compilador de C/C++. Hay que emplear un compilador externo para conseguir la aplicación.

Si se usa Linux o MacOSX, se deberá ejecutar “make” en el símbolo del sistema, y se procesarán, compilarán y enlazarán los archivos hasta obtener el ejecutable.

Si se usa Windows y la versión LGPL de Qt , se deberá ejecutar “mingw32-make”, porque se emplea el compilador GNU gcc portado a Windows.

Si se quiere desarrollar para Windows Mobile o Windows con el compilador de Microsoft Visual C++, se deberá ejecutar “nmake”.

En este tutorial se emplea la versión LGPL de Qt y, por tanto, por debajo está el compilador de GNU gcc portado a Windows.

Ahora hay que utilizar el compilador externo que se haya configurado para procesar los archivos de guión de C/C++. Estos archivos tienen el nombre Makefile.* y son de texto, así que estaría bien que echarle un vistazo por dentro para entender un poquito más la idea (y asustarte).

Para procesar el archivo de guión de C/C++ se hará:

c:\...> mingw32-make

Y saldrán un montón de lineas y, al rato, dirá que ya está todo hecho (con suerte).

Si has copiado el programa a mano, seguro que salen un montón de errores y, para corregirlos, tendrás que esforzarte en entender qué falla. Vale la pena que lo intentes corregir así esta vez. Aprenderás mucho.

Aquí una imagen de lo que sale:

Figure 2. Salida de "make"

Salida de "make"

Ahora se probará si todo a ido bien. Se deberás cambiar al directorio debug y ejecutar el programa de la siguiente manera:

C:\...> cd debug
C:\...> qt_per_tots.exe

Y, tachaaaaaannnnnnnnnnnnnn. ¡¡¡¡¡¡Funcionannndooooo!!!!!!.

[Note]Note

No funcionará si se hace clic desde el explorador de Windows. En la sección de preguntas frecuentes está la razón.

4. La colección de ventanucos

Año tras año se va ampliando la colección de plataformas donde se ha probado la guía. Ahí va eso.

Figure 3. Microsoft Windows XP

Microsoft Windows XP

Figure 4. Microsoft Windows Vista

Microsoft Windows Vista


Figure 5. Linux Ubuntu 8.04 con desktop Gnome

Linux Ubuntu 8.04 con desktop Gnome


Figure 6. Nokia N82 con Symbian S60 3rd edition

Nokia N82 con Symbian S60 3rd edition


Figure 7. Nokia N900 con Linux Maemo 5

Nokia N900 con Linux Maemo 5


Figure 8. MacOS Lion

MacOS Lion


Figure 9. Arch Linux con desktop KDE

Arch Linux con desktop KDE


5. Me pierdo. ¡Ayuda!

Ahora ya es momento de empezar a utilizar la bibliografía recomendada.

En cualquier caso, destacar que Qt incluye una ayuda muy completa y es un buen momento para echarle un vistazo. Éntrese en la página de Qt y accédase a la sección de documentación. En principio, se debería poder llegar fácilmente a la siguiente página:

Figure 10. Ayuda estándar de Qt

Ayuda estándar de Qt

Este es un buen punto de partida para empezar a hacerse una idea sobre la filosofía de Qt y echar un vistazo a las clases. Destacar que ésta es la misma ayuda que se obtiene al instalar el entorno Qt SDK completo.

6. Y ahora con Qt Creator

En apartados anteriores se ha creado un proyecto Qt completo, se ha procesado con qmake para generar los archivos necesarios para compilarlos en la plataforma destino, y se ha construido el proyecto. Todo ello se ha realizado desde la "línea de órdenes" con la única intención de tener más claro todo el proceso.

Usar un entorno de desarrollo integrado (IDE) puede facilitar enormemente la gestión de código y, precisamente Qt Creator se ha desarrollado con esa intención.

Qt Creator no es Qt, es un potente IDE desarrollado por Nokia con la intención de facilitar las tareas habituales de edición, compilación, depurado, etc. Por debajo, hará exactamente lo que hemos hecho nosotros en el paso anterior.

Hay otros entornos abiertos que permiten hacer lo mismo que Qt Creator, por ejemplo, KDevelop, CodeBlocks o Eclipse, pero Qt está tan bien integrado con Qt que es la mejor opción para empezar. De hecho, es tan bueno que, últimamente, lo uso para el desarrollo de aplicaciones para microcontroladores 8051 y Cortex-M3.

Para empezar, se va a "abrir" nuestro programa desde Qt Creator, para ello, ejecútese Qt Creator, ir a Archivo->Abrir, desplazarse hasta la carpeta donde está nuestro proyecto, y abrir el archivo qt_per_tots.pro. Con ello se logra gestionar fácilmente el proyecto y editar los fuentes C++, compilar, ejecutar, etc. Ver abajo como queda.

Figure 11. Qt Creator con nuestro proyecto abierto

Qt Creator con nuestro proyecto abierto

Para practicar más, se propone aprender a crear un proyecto vacío y añadir las piezas después siguiendo estos pasos:

  • Crear un nuevo proyecto con el menú New->"Qt project vacío".

  • Copiar los módulos C/C++ anteriores a la carpeta de proyectos que se ha creado.

  • Añadir al proyecto los archovos con la opción "Add files".

  • Probar a compilar el proyecto. Aprovechar también para echar un vistazo al .pro que ha generado Qt Creator.

7. Dando vida: señales y ranuras (signal y slot)

7.1. La idea

La filosofía de Qt se basa en enriquecer las clases C++ con un mecanismo propio de "señales" y "ranuras" que permite que los objetos interactúen.

Una señal (signal) será información que pueden enviar "al aire" los objetos Qt que deriven de la clase QObject.

Una ranura (slot) es un posible receptor de señales. Para que un slot pueda recibir una señal se deben cumplir dos cosas:

  • que se haga una conexión

  • que la signal y el slot sean compatibles

Gráficamente, se podrían representar las señales y las ranuras de un objeto como en la siguiente figura:

Figure 12. Un botón con algunos slots y signals

Un botón con algunos slots y signals

Para hacer las conexiones entre los elementos de Qt, se usará el método connect() de QObject con la siguiente sintaxis:

7.2. Conectando cosas de nuestra ventana

Como ejemplo, se puede conectar la señal clicked() del botón "Salir" de nuestro Tventanuco al slot close() de QDialog, que es de quien deriva TVentanuco. El código se podría meter al final del constructor de TVentanuco.

    // para cerrar el diálogo
    connect(btCerrar,SIGNAL(clicked()),this,SLOT(close()));

También se podría conectar ahora la señal clicked() del botón "Toquetear" al slot clear() de la línea de edición leEdicion de la siguiente manera.

    // para borrar la linea de edición al pulsar un botón
    connect(btToquetear,SIGNAL(clicked()),leEdicion,SLOT(clear()));

Las conexiones se pueden hacer de muchas formas, permitiéndose que una señal vaya a distintos slots o, incluso, conectar una señal con otra. Eso es mejor mirarlo en un libro para Qt.

[Important]Important

Hay que tener siempre la precaución de que la signal y el slot sean compatibles y tengan los mismos parámetros. Si no es así, el programa se compilará y se ejecutará sin problemas, pero no funcionará correctamente.

7.3. Mi propio "slot"

El mecanismo signal/slot permite que las clases derivadas de QObject interactúen entre sí. Todo esto está muy bien, pero ¿cómo se consigue ejecutar mi propio código al pulsar un botón?.

La respuesta en Qt es crear nuestras propias signal y slot con nuestro código y hacer las conexiones adecuadas.

Se empezará con los slot. Supóngase que se desea escribir un texto fijo en la línea de edición al pulsar el botón "Toquetear".

Lo primero es ir a la definición de la clase TVentanuco y meter un método en una nueva sección que se llamará public slots.

class TVentanuco : public QDialog {
 ...
 public slots:
    void ranura_saludo(void);
}

Ésta es la manera de crear un slot.

La implementación consiste en implementar un método normal y corriente, por ejemplo:

//-- implementacion un slot de la misma manera que un metodo normal 
void TVentanuco::ranura_saludo(void) {

   lbEtiqueta->setText(tr("!Buenos días!")); 

}

Ahora se puede hacer la conexión. Por ejemplo, en el constructor de TVentanuco se haría:.

    connect(btToquetear,SIGNAL(clicked()),this,SLOT(ranura_saludo()));

Y se prueba, claro.

Los slots se pueden crear en cualquiera de las secciones habituales de las clases C++: public slots, private slots y protected slots.

[Important]Important

Destacar que los métodos creados como slots se pueden usar tanto con el mecanismo signal/slot como con llamadas normales a métodos. De hecho, lo que se suele hacer es que los métodos más habituales de una clase se los convierte a slots para permitir la interacción entre objetos Qt.

7.4. Mi propia "signal"

Ahora vamos con las señales.

Imagínese que se quiere que TVentanuco sea capaz de enviar una signal con un mensaje en ella usando el prototipo senyal_estornudo(const char*).

Para crear esta señal, se irá a la definición de la clase TVentanuco y se añadirá una nueva sección llamada signals.

class TVentanuco : public QDialog { 
... 
signals:
  void senyal_estornudo(const char*); 
... 
}

El nuevo método no hace falta implementarlo, solo se necesita "emitir" la señal en el momento deseado. Para ello se deberá añadir el siguiente código en algún punto de la implementación de TVentanuco:

 ...
 emit senyal_estornudo(parametros);
 ... 

Así de fácil.

7.5. Probando: estornudos y microbios

Se va a intentar ilustrar el mecanismo con un ejemplo más completo en el que se intentará que dos instancias de TVentanuco interactúen entre sí. Para ello se propone lograr que las dos instancias intercambien información según se ilustra en la siguiente figura. Donde las señales representan "microbios" que se lanzan al aire y los slots representan "receptores" de esos microbios.

Figure 13. Diagrama de conexiones

Diagrama de conexiones


Para ello se propone añadir a TVentanuco un slot con la definición void ranura_infeccion(const char*) cuya implementación haga que, cuando llegue algo, se muestre en el título de la ventana de diálogo.

La definición del slot podría ser:

class TVentanuco : public QDialog {
 ...
 public slots:
   void void ranura_infeccion(const char*); 
}

Y su implementación:

// un slot por el que pueden llegar "microbios" desde el exterior
void TVentanuco::ranura_infeccion(const char* nombre_microbio) {

        setWindowsTitle(nombre_microbio);

    }

Ahora supongamos que deseamos crear el escenario mostrado antes, donde se interconectan entre sí las señales de senyal_estornudo() y los slots de ranura_infeccion() de los 2 TVentanuco de nuestro ejemplo.

En este caso, las conexiones se deberán hacer en el programa principal después de haber creado los dos TVentanuco. Por ejemplo, de la siguiente manera:

// estornudantes y estornudados conectados
QObject::connect(vent1,SIGNAL(senyal_estornudo(const char*)),&vent2,SLOT(ranura_infeccion(const char*)));
QObject::connect(&vent2,SIGNAL(senyal_estornudo(const char*)),vent1,SLOT(ranura_infeccion(const char*)));

Para que se emita la señal senyal_estornudo(), se deberá añadir código a TVentanuco. Por ejemplo, se podría asociar a un nuevo slot conectado al botón btToquetear cuya implementación podría ser:

//-- vamos a estornudar cada 5 veces que se entra en esta funcion ------------
void TVentanuco::ranura_cosquillas(void) {

    static int i = 0;

    i++;
    if (i == 5) {
        i = 0;
        emit senyal_estornudo("Streptococus burrus");
    }
}

8. Diseñando ventanas con el ratón

8.1. El planteamiento

Muchos están acostumbrados a utilizar herramientas de arrastrar-y-soltar para el diseño de ventanas, la colocación de objetos gráficos y la manipulación de sus propiedades. La propuesta es ampliar la aplicación ejemplo e incluir en ella una ventana diseñada de esta forma.

En Qt se puede emplear la herramienta Qt Designer para trabajar de esta manera. Esta herramienta nos proporcionará un "formulario" en bruto que podremos incorporar a cualquiera de los contenedores típicos de Qt como son QDialog, QMainWindow, QSplah, etc. La siguiente figura ilustra la idea que se va a poner en práctica e los siguientes apartados:

Figure 14. Combinando un formulario de Designer con un QDialog

Combinando un formulario de Designer con un QDialog

8.2. El formulario con Qt Designer

Para crear un formulario desde Qt Creator, elegir el menú "nuevo" y seleccionar "Formulario Qt Designer". Después elegir "Dialog without buttons" e ir aceptando las opciones por defecto. Dar de nombre al archivo FdsgnVentanuco.ui. Como resultado se incorporará a nuestro proyecto un archivo con la extensión .ui (de user interface) y se abrirá la ventana de Qt Designer.

Figure 15. Asistente para la creación de formularios

Asistente para la creación de formularios

Como ya se está acostumbrado a trabajar con el estilo de arrastrar-y-soltar, rápidamente se le cogerá el truco al entorno. La propuesta es preparar algo parecido a TVentanuco usando el ratón, y teniendo en cuenta el siguiente detalle:

[Important]Important

El nombre del elemento gráfico dentro de nuestro código se corresponde con la propiedad objectName del elemento.

Dicho esto, se propone usar los mismos que en TVentanuco. Para el formulario contenedor se propone el nombre FdsgnVentanuco (de Formulario-designer-Ventanuco).

La siguiente figura muestra cómo puede quedar la cosa.

Figure 16. Creando el diálogo

Creando el diálogo

La herramienta puede estar en varios modos. Para ir al grano, interesan el modo edición de objetos gráficos y el modo edición de signal/slot. Para pasar de un modo a otro se pueden usar las teclas F3 y F4, o los iconos que se ven en la parte superior de la ventana de Qt Designer.

Pásese ahora al modo signal/slot. Pínchese en el botón "Salir", arrástrese hasta la superficie del diálogo y suétese. Deberá aparecer un diálogo para que se pueda seleccionar una conexión.

Figure 17. Conectando signals y slots en Qt Designer.

Conectando signals y slots en Qt Designer.

Algunas señales no aparecen a la primera, por ejemplo, si se quiere conectar el clicked() sobre el botón, con el close() del diálogo. La razón es que hay muchas señales, así que en la ventana salen solo las más comunes. Márquese en "Mostrar todas las señales" o similar para ver las requeridas.

Como práctica adicional, podemos se puede conectar clicked() del botón btToquetear con clear() de leEdicion.

Figure 18. Más signals y slots en Qt Designer.

Más signals y slots en Qt Designer.

Para hacerse una idea más clara de cómo se debe trabajar con Qt Designer vale la pena echar un vistazo a los vídeos disponibles en http://gumuz.nl. Quizá no se entiendan algunas cosas, pero para eso están los libros y no esta guía rápida.

Enlaces directos a los vídeos: parte 1 y parte 2.

8.3. Pasándole la moto al formulario con uic

El formulario que se ha creado forma ya parte del. Se puede echar un vistazo a qt_per_tots.pro para ver que se ha añadido la siguiente línea.

FORMS+=FdsgnVentanuco.ui

Por supuesto, este FdsgnVentanuco.ui se puede copiar e incorporar a cualquier otra aplicación que se desarrolle para Qt. Es interesante echarle un vistazo por dentro y darse cuenta que es XML y se puede entender.

En general, antes de poder usar el formulario, este debe ser convertido a C++ con una herramienta de Qt llamada llamada uic (user interface compiler) convierte nuestro .ui a C/C++ generando un fichero de cabecera que empieza siempre por ui_ seguido del nombre de la propiedad objectName de diálogo contenedor. En nuestro caso será ui_FdsgnVentanuco.h.

Pruébese a construir el proyecto y localícese dicho archivo, que suele colocarse en el directorio de construcción. Es muy importante para captar la idea que se miren las tripas de este archivo, pues se verá que, "simplemente", se ha fabricado código para colocar los elementos gráficos.

En el archivo generado automáticamente habrá dos métodos:

  • void setupUi(QDialog *FdsgnVentanuco): para crear y colocar los elementos gráficos.

  • void retranslateUi(QDialog *FdsgnVentanuco): para ser llamado cuando se cambia de idioma la aplicació en vivo, por ejemplo, de "català" a "chino simplificado".

8.4. Creando una clase para contener el formulario

Como ya se ha indicado, el formulario debe ser incorporado a un contenedor para ser mostrado. En nuestro caso, el contenedor que se propone va a ser un QDialog.

Hay distintas maneras de hacer esto, incluso es tema de discusión en distintos foros. La opción que se propone aquí es una de las oficiales.

Lo primero es definir la nueva clase, y se propone crear entonces el siguiente archivo de cabecera.

// Fichero: TdsgnVentanuco.h
// Clase derivada de QDialog
// y que incluye un formulario hecho con Qt Designer
// DSII. Curso 2011/2012

#ifndef TDSGNVENTANUCO_H
#define TDSGNVENTANUCO_H

#include <QDialog>
#include "ui_FdsgnVentanuco.h"  // este fichero lo ha creado automaticamente "uic"

// Un "namespace" permite  meter nombre de cosas en un espacio separado
namespace Ui {
    class TdsgnVentanuco;
}

class TdsgnVentanuco : public QDialog
{
   Q_OBJECT

public:
    TdsgnVentanuco(QWidget *parent = 0);
    ~TdsgnVentanuco();

public slots:
    void saludo(void);

private:
    Ui::FdsgnVentanuco *ui; // la parte de designer queda en el espacio de nombres
};

#endif // DERIVADO_DESIGNER_H

Observar cómo se incluye la cabecera generada por uic, y como se "privatiza" el formulario para que no se pueda manipular desde el exterior, siguiendo un buen estilo de programación.

Para ir adelantando cosas, también se ha añadido un slot propio que después usaremos.

El siguiente listado corresponde a la implementación de la clase derivada.

// Fichero: TdsgnVentanuco.cpp
// Clase derivada por herencia múltiple de QDialog y de un formulario hecho con Qt Designer
// DSII. Curso 2011/2012

#include <QtGui>

#include "TdsgnVentanuco.h"

// constructor de la clase -----------------------------------------------------------------
TdsgnVentanuco::TdsgnVentanuco(QWidget *parent) :
    QDialog(parent),            // construir el QDialos
    ui(new Ui::FdsgnVentanuco)  // construir el designer
{
    ui->setupUi(this);          // necesario para mostrar el Designer

    // ejemplo de conexión de un slot definido por el usuario
    connect(ui->btToquetear,SIGNAL(clicked()),this,SLOT(saludo()));
}

// destructor de la clase -----------------------------------------------------------------
TdsgnVentanuco::~TdsgnVentanuco()
{
    delete ui;
}

// un método publico que es un slot -------------------------------------------------------
void TdsgnVentanuco::saludo(void) {
    // enviamos el mensaje al titulo del dialog
    setWindowTitle(tr("Bon dia pel matí"));
    ui->lbEtiqueta->setText(tr("Hola"));
}

Observar que lo primero que se hace en el constructor es llamar a la función setupUi(). La llamada a esta función es obligatoria para que se configure adecuadamente el diálogo.

En la implementación del slot se puede ver que no hay ningún inconveniente en acceder a los miembros del formulario diseñado con el ratón. A destacar el hecho de que ahora el acceso a los miembros de los formularios ha cambiado, debiento anteponer el objeto contenedor ui que se crea dinámicamente. En cristiano:

// donde ponía btCerrar->setText(tr("Bon dia"));
// deberé poner

ui->btCerrar->setText(tr("Bon dia"));

8.5. Usando el nuevo diálogo

Este clase se puede usar igual que la primera en el programa principal. En el siguiente listado se ve un ejemplo:

// Fichero: main.cpp
// ...

#include "TdsgnVentanuco.h"

int main(int argc, char *argv[]) {
        // ...
        TdsgnVentanuco *vent3;

        // ...
        vent3 = new TdsgnVentanuco(NULL);
        vent3->show();

        // ...

        return(app.exec());
 }

9. ¿Hasta dónde puedo llegar con Qt?

Coge el Tventanuco y introduce las siguientes modificaciones.

En qt_per_tots.pro:

//...

Qt += webkit

//...

En tventanuco.h:

//...
// declaraciones "forward" de C/C++ para acelerar la compilación
//...class QPushButton;
class QWebView;

// a derivar de QDialog
class TVentanuco : public QDialog
{

public slots:
    void navega(void);

private:
    // vamos a meter unas cuantas cosas
    QWebView *wvNavegador;

//...

En tventanuco.cpp:

#include <QtWebKit>

// constructor de la clase, se llama también al constructor del padre
TVentanuco::TVentanuco(char *mensaje):QDialog()
{
    //...
    // parar jugar con los "layout", meto un "muelle"
    lyDistribuidor->addStretch();

    // un visualizador de páginas web
    wvNavegador = new QWebView();
    //wvNavegador->setWindowTitle("xxx");
    wvNavegador->load(QUrl("http://www.upv.es/"));
    lyDistribuidor->addWidget(wvNavegador);

    // para borrar la linea de edición al pulsar un botón
    // connect(btToquetear,SIGNAL(clicked()),leEdicion,SLOT(clear()));

    // para escribir un texto en la linea de edición al pulsar un boton
    // en este caso hace falta crear slot propio
    //connect(btToquetear,SIGNAL(clicked()),this,SLOT(saludo()));

    // navegador web
    connect(btToquetear,SIGNAL(clicked()),this,SLOT(navega()));

}

//implementacion un slot de la misma manera que un metodo normal
void TVentanuco::navega() {
    QString url_str;

    url_str = "http://";
    url_str = url_str + leEdicion->text();
    wvNavegador->load(QUrl(url_str));
}

Y el resultado en la siguiente imagen.

Figure 19. Aspecto del nuevo TVentanuco

Aspecto del nuevo TVentanuco

Ahora tienes un navegador de paginas web que has hecho en unos minutos. Imagina pues.

Y también lo puedes meter en el móvil:

Figure 20. El Tventanuco navegador en el Nokia N900

El Tventanuco navegador en el Nokia N900

Imagina aún más.

10. ¿Y ahora qué?

Ahora es el momento de empezar a aprender Qt con un buen libro. Para este curso recomendamos el de Molkentin.

11. Y para crear rapidito los proyecto de DSII

Todo lo anterior debe servir para entender la filosofía Qt. Una vez entendido, se pueden hacer las cosas de una manera más automática aprovechándose de las plantillas que vienen con Qt Creator.

Se propone seguir los pasos mostrados en los siguientes vídeos para crear el esqueleto de los programas para las practicas de la asignatura:

Una manera aún más rápida de crear y conectar slots propios es aprovecharse de un mecanismos adicional de autoconexión consistente en escribir los métodos usando palabras mágicas.

Prueba lo siguiente:

  • ve a formulario de Qt Designer

  • pincha en btToquetear y saca el menú contextual

  • elige "go to slot ..." y selecciona la señal

  • tacháaaannnn!! ya tienes creado el slot y que se conectará el solito automáticamente

Con este mecanismo, tendremos algo muy familiar si venimos de VisualBasic, Borland Builder o Borland Dephi. El nombre de la función usará las "palabras mágicas" para que se realice la conexión. Por si las mosca, ahí va el fragmento que se debería crear en el módulo de implementación:

void TdsgnVentanuco::on_btToquetear_clicked()
{
    
}

12. Descargas

13. Preguntas frecuentes

Según van saliendo pegas con Qt y las vamos solucionando lo apuntamos en preguntas frecuentes de Qt.

14. Bibliografía y enlaces

Libros recomendados:

  • Molkentin, Daniel "book of Qt 4". Munich ; San Francisco : Open Source Press:1593271476 : 2007

  • Blanchette, Jasmin, Summerfield, Mark "C++ GUI programming with Qt 4. 2nd edition" Prentice Hall:0132354160 : 2008

En castellano no hay nada, que yo sepa.

El la página de Qt hay una lista de libros: http://qt.nokia.com/developer/books

Bon profit!.