Está en la página 1de 24

Desarrollo Rápido de Aplicaciones

usando Qt/KDE y KDevelop


por:
José Pablo Ezequiel “Pupeno” Fernández
E-Mail: pupeno@pupeno.com
IM: pupeno@jabber.org
Web: www.pupeno.com
Versión: 0.1.4
Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

Tabla de Contenidos
Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop.................................1
1 Introducción al desarrollo rápido de aplicaciones................................................3
1.1 Que es Qt?.......................................................................................................3
1.2 Que es KDE?...................................................................................................3
1.3 Que es KDevelop?...........................................................................................3
1.4 Que es Designer?............................................................................................4
2 Inicios en programación Qt/KDE (o primeros pasos en KDevelop).......................4
2.1 Creando el proyecto........................................................................................4
2.2 Compilando la aplicación................................................................................5
2.3 Anatomía del Ejemplo1...................................................................................5
2.4 main.cpp.........................................................................................................6
2.5 La ventana principal.......................................................................................7
2.6 Conectando.....................................................................................................9
2.7 Acciones, un objeto, muchas representaciones............................................12
2.8 Nuestro widget Ejemplo1View.....................................................................15
3 Diseñando GUIs con Designer.............................................................................16
3.1 Creando un widget........................................................................................16
3.2 Poniendo widgets en nuestro widget............................................................17
3.3 Layouts, dinamismo a nuestra ventana.........................................................18
3.4 Widgets contenedores...................................................................................19
3.5 Layouts avanzados........................................................................................19
3.6 Funciones, slots y signals en Designer.........................................................21
3.7 Conexiones en Designer................................................................................22
3.8 Integrando Designer en KDevelop................................................................22
4 Conclusión...........................................................................................................23

José Pablo Ezequiel Fernández Página 2 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

1 Introducción al desarrollo rápido de


aplicaciones
El desarrollo rápido de aplicaciones también conocido como RAD por su nombre en
ingles, Rapid Application Development es una serie de métodos que nos sirven para
desarrollar aplicaciones o programas de computadora a gran velocidad. El
nacimiento de RAD esta basado principalmente en dos hechos:
1. Cada vez la potencia de computo (potencia de los procesadores) es más barata y
la mano de obra es más cara por eso, conviene que el desarrollador haga su
trabajo lo más rápido posible aunque no sea, el resultado, todo lo eficiente que
podría ser, ya que las computadoras que van a ejecutar esos programas tienen
potencia de sobra para realizarlo.
2. La complejidad de desarrollar aplicaciones amigables que posean una GUI
(Graphic User Interface o “Interfase Gráfica de Usuario”) que manejen
correctamente las enormes cantidades de datos que se manejan hoy en día y se
integren correctamente con el escritorio es muy grande. Sin el automatismo y los
conceptos de RAD seria muy difícil llevar a cabo la tarea de realizar aplicaciones y
mantenerlas actualizadas posteriormente.
Este documento es una introducción a RAD en Linux con Qt/KDE utilizando
KDevelop por lo tanto es recomendable que el lector sepa programar en el lenguaje
C++ y que tenga conocimientos básicos de programación orientada a objetos. La
orientación del documento va a ser puramente hacia la programación y no hacia el
uso de programas así que cuando se responden preguntas como ¿Que es Qt? o ¿Que
es KDE? las respuestas son para programadores y no para usuarios.

1.1 Que es Qt?


Qt es una biblioteca orientada a objetos, multiplataforma desarrollada en C++ por
TrollTech que además de proveernos las clases para los objetos gráficos, nos provee
también muchas otras clases útiles para manejo de datos, como cadenas de
caracteres, listas, vectores, colas, uso de SQL, etc. Qt esta bajo licencia GPL para
plataformas Unix (incluyendo Linux) y MacOS así como también bajo su propia
licencia, QPL. Para realizar aplicaciones comerciales, se puede comprar una licencia
comercial.

1.2 Que es KDE?


KDE es un “entorno de escritorio”. Pero para los programadores, es una serie de
bibliotecas que extienden las capacidades de Qt aportando nuevas cualidades así
como una excelente integración e interacción entre aplicaciones. KDE aporta
muchas tecnologías como KParts, DCOP, Arts, MCOP, etc.

1.3 Que es KDevelop?


KDevelop es una IDE, Integrated Development Environment (o “Entorno Integrado
de Desarrollo”). Básicamente nos hace la vida mas fácil al ser un solo programa que
nos provee de un editor de texto con resaltamiento de sintaxis, completado
automático, encarpetado de funciones, así como también un administrador de
proyecto, un visualizador de clases en forma de árbol, integración con CVS,
integración con los compiladores, integración con otros programas de interés, como
Designer.

José Pablo Ezequiel Fernández Página 3 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

1.4 Que es Designer?


Designer a pesar de que hoy en día tiende a ser una IDE para Qt, principalmente es
una aplicación WYSIWYG (What You See Is What You Get o “lo que ves es lo que
obtienes”) para desarrollos de GUI. Básicamente con Designer podemos crear
ventanas y poner los objetos (botones, listas, etc) dentro de ellas arrastrándolos y
soltándolos y ver en el momento, como va a quedar.

2 Inicios en programación Qt/KDE (o primeros


pasos en KDevelop)
En este documento trabajaremos con la versión 3.0.1 de KDevelop que es la última
publicada hasta el momento de escribir este documento.
KDevelop incluye muchos tipos de proyectos entre los cuales encontramos Ada, C
(en el cual existe la posibilidad de crear un proyecto Gnome), C++ (el único que nos
interesa ahora), Fortran, Java, PHP, Pascal, Perl, Python, Ruby y Shell. En C++
también tenemos varios tipos: Embedded, KDE (el que nos interesa ahora),
KDevelop, QMake, Simple C++, SDL y wxWindow y dentro de KDE todavía tenemos
más subdivisiones: Application Framework, Application Framework (KParts) y
muchos más.

2.1 Creando el proyecto


Inicialmente vamos a crear una aplicación C++->KDE->Application Framework que
es la que deberíamos usar como base para la mayoría de las aplicaciones KDE.
Para hacerlo seleccionamos nuestra opción
(C++->KDE->Application Framework) de la
lista y luego procedemos a llenar el resto de
los datos. El nombre de la aplicación puede
contener letras mayúsculas, pero no espacios
en blanco (el nombre que va a aparecer luego
en los menús y en las barras de titulo puede
cambiarse), pero para generar el directorio de
la aplicación y los archivos se va a pasar todo
a minúsculas no obstante se va a dejar como
está para los nombres de las clases. También
elegimos el directorio donde lo va a crear
(adentro de ese directorio va a crear un
directorio con el nombre de la aplicación
como dice en “Localización final”), luego
ponemos nuestro nombre, nuestra dirección
Figura 1: Creando un nuevo proyecto
de correo electrónico, la versión inicial y que llamado Ejemplo1 con KDevelop.
licencia vamos a usar.
Luego solo nos pregunta si vamos a usar algún sistema de control de versiones (no
será tratado en este documento) como CVS, CvsService o Subversion y nos ofrece la
posibilidad de cambiar los comentarios de encabezado para los archivos .h y .cpp y
ya tenemos una aplicación lista (para compilar).

José Pablo Ezequiel Fernández Página 4 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

2.2 Compilando la aplicación


Luego de crear la aplicación, esta, no esta compilada, para hacerlo, podemos ir al
menú Construir->Construir Proyecto (Build->Build Project en ingles) o presionar F8.
En ese momento, nos va a aparecer una ventana diálogo que nos informa que no hay
ningún Makefile en el directorio así como ningún script configure. Esto es por que el
proyecto es creado con un Makefile.cvs que solo debe permanecer en la versión en
desarrollo (no hace falta distribuirlo) que se encarga de ejecutar las utilidades
(automake y autoconf) que generan el script configure que al ejecutarlo genera el
Makefile que nos permite simplemente ejecutar make para compilar un proyecto.
Este complicado sistema existe para asegurar la portabilidad del sistema (libtool es
utilizado). Simplemente aceptando
nuestro programa es compilado.
Haciendo click derecho en la ventana
donde KDevelop muestra los
mensajes, podemos elegir cuanto de
Figura 2: Ventana de compilación al empezar a
los mensajes podemos ver, teniendo compilar Ejemplo1.
opciones donde se muestran mensajes
muy simples y escuetos hasta ver directamente las lineas de
compilación (como si lo hiciéramos en una terminal), así
como también podemos agregar la opción de ver los
mensajes de navegación de directorios. En la figura 2
podemos ver esa ventana.
Simplemente presionando mayúsculas F9 (Construir-
>Ejecutar Programa o Build->Execute Program en ingles)
podemos ver nuestra nueva aplicación ejecutándose. La
aplicación debería verse como en la figura 3.
La aplicación seguramente fue compilada en modo debug, lo
cual significa que tienen lo símbolos en los ejecutables, para Figura 3: esta es
nuestra aplicación,
que cuando la aplicación falle, sea más fácil hacer un trace.
llamada Ejemplo1
Si la queremos en modo optimized (para distribución), ejecutándose por
tenemos que ir a Proyecto->Configuración de Construcción primera vez.
(Project->Build Configuration) y elegir optimized entre las
opciones.

2.3 Anatomía del Ejemplo1


La recientemente creada aplicación puede parecer un poco compleja al principio,
sobre todo para el que recién comienza con este tipo de programación, pero si se la
analiza paso a paso se podrá ver que no es tan compleja.
Inicialmente nuestra aplicación tiene 6 clases:
• Ejemplo1: Es la clase que va a formar nuestra ventana principal, hereda
KMainWindow esta declarada en ejemplo1.h y definida en ejemplo1.cpp. Es la
encargada de disponer los menús, las barras de herramientas, la barra de estado,
abrir archivos, imprimir archivos, cerrar archivos, abrir una nueva ventana, etc.
• Ejemplo1View: Es la clase que forma la parte central de la aplicación, donde la
acción realmente ocurre, hereda QWidget. Eso quiere decir, que según la
biblioteca Qt, esta clase es un widget (un widget es un objeto gráfico que se usa
para formar la GUI, como botones, listas despegables, botones radio, botones de
chequeo, etc). Los widgets pueden ser más complejos conteniendo otros widgets

José Pablo Ezequiel Fernández Página 5 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

adentro). Esta clase es declarada en ejemplo1view.h y definida en


ejemplo1view.cpp.
• Ejemplo1Preferences: Es el diálogo de configuración de nuestra aplicación.
Hereda KDialogBase que es una clase diseñada para crear diálogos. Esta clase es
declarada y definida en pref.h y pref.cpp respectivamente.
• Ejemplo1PrefPageOne: Heredando QFrame esta clase constituye la primer página
del diálogo de configuración. Esta clase es declarada y definida en pref.h y
pref.cpp respectivamente.
• Ejemplo1PrefPageTwo: Heredando QFrame esta clase constituye la segunda
página del diálogo de configuración. Esta clase es declarada y definida en pref.h y
pref.cpp respectivamente.
• Ejemplo1Iface: Esta es la única clase de nuestro Ejemplo1 que no es un widget.
Esta clase es la interfase DCOP (Desktop COmunication Protocol o Protocolo de
Comunicación de Escritorio) de nuestro programa. Hereda DCOPObject y permite
a otros programas (incluyendo desde la shell) llamar a funciones de nuestro
programa y así controlarlo desde afuera.
Todos los archivos nombrados se encuentran en la carpeta src de nuestro proyecto.
Hay un archivo más de código fuente (también hay algunas imágenes para los
iconos, los Makefiles y hasta un README que por ahora no nos interesan) que es
llamado main.cpp que como es de esperarse contiene nuestra función main() y
algunas declaraciones.
Las aplicaciones que tienen GUI tienen un aspecto muy distinto al resto y que se
puede definir como asincronismo. Estas aplicaciones al iniciarse simplemente
muestran una o más ventanas con una serie de botones y acciones para que el
usuario maneje la aplicación. Cada una de las acciones que el usuario lleva a cabo
se transformar en una función que es ejecutada en nuestro programa, lo que nos
lleva a preguntarnos ¿Que función se ejecuta mientras el usuario no esta haciendo
nada? La respuesta a esta pregunta se la puede encontrar analizando main.cpp y la
primer función, main().

2.4 main.cpp
Este archivo contiene la función main() de nuestro programa y algunas definiciones
de constantes, como la versión de nuestra aplicación, la descripción (para lo cual se
usa la macro de traducción I18N_NOOP) y los parámetros que puede recibir como
comando.
Lo primero que hace la función main es crear un objeto KAboutData que es el
encargado de almacenar información sobre nuestro programa que puede ser vista
yendo al menú Help->About Ejemplo1 (Ayuda->Sobre Ejemplo1).
Luego de agregar los autores al objeto KAboutData y de inicializar los parámetros de
la linea de comando viene una de las lineas más importantes:
KApplication app;
Esta linea crea el objeto app de la clase KApplication que es la clase madre de
nuestra aplicación. KApplication nos provee el control del bucle de eventos, la
función que se ejecuta mientras el usuario no esta haciendo nada y de otros recursos
como 'aceleradores', items de menú más comunes, un objeto KConfig (para la
configuración de nuestra aplicación), manejo de sesión, etc.

José Pablo Ezequiel Fernández Página 6 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

Luego se registra la aplicación en DCOP, se verifica si la aplicación es restaurada


por el manejador de sesión y en base a la existencia o no de parámetros se realizan
diferentes tareas, pero basícamente lo mismo:
Ejemplo1 *widget = new Ejemplo1;
widget->show();
esto crea el objeto widget desde la clase Ejemplo1 y lo muestra en pantalla
ejecutando la función show(). Luego sólo resta ejecutar el bucle de eventos con la
linea app.exec() que hace que 'la rueda empiece a rodar'.

2.5 La ventana principal


En la mayoría de las aplicaciones GUI tenemos una ventana principal que es la
primera que aparece cuando el usuario ejecuta la aplicación. Esta ventana suele
tener una serie de elementos que otras no tienen, como un barra de menú (que suele
estar colocada arriba), una barra de estado (que suele estar colocada abajo), barras
de herramientas, bloques de herramientas, etc. Y en el centro de todo, los elementos
que nos van a permitir hacer nuestro trabajo.
La ventana principal, así como cualquier otro elemento GUI, es un widget. Para
hacerla creamos una clase que herede KMainWindow (clase desarrollada
específicamente para ese fin). Bien podríamos crear nuestra ventana principal desde
la clase QWidget (que es el widget más básico que hay) pero nos perderíamos todos
los extras que provee KMainWindow.
Examinando la declaración de Ejemplo1, lo primero que nos llama la atención es que
la primer linea de la clase es:
Q_OBJECT
Q_OBJECT permite al moc (Meta Object Compiler o Meta Compilador de Objeto)
saber que esto es un objeto Q y que por lo tanto tiene que activar el sistema de
signals y slots para él (se verá más adelante). Todos los widgets, ya sean de Qt, KDE
o propios, tienen que ser, si o si, objetos Q. Por lo tanto Q_OBJECT tiene que estar al
principio de la declaración de cada uno de nuestros widgets.
Las primeras dos funciones declaradas son el constructor y el destructor de la clase:
/**
* Default Constructor
*/
Ejemplo1();

/**
* Default Destructor
*/
virtual ~Ejemplo1();
Los comentarios comenzando con /** (un asterisco más de lo necesario) son
comentarios de documentación. Estos comentarios pueden ser compilados por
programas como Doxygen (el más utilizado al realizar programación C/C++) y
generar la documentación del API como lo podemos ver aca:
http://developer.kde.org/documentation/library/cvs-api/kdeui/html/index.html. Es
recomendable, inclusive en las funciones privadas de las clases, utilizar
documentación de este tipo, ya que la compilación de la documentación puede

José Pablo Ezequiel Fernández Página 7 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

servirnos en el futuro a nosotros u a otros desarrolladores que quieran o tengan que


modificar nuestra aplicación (obviamente, si hacemos bibliotecas de uso genérico,
una buena documentación para quienes la van a usar es esencial).
La función que sigue es
void load(const KURL& url);
y representa una de las pocas funcionalidades que tiene nuestra clase Ejemplo1 ya
implementada. Esta función abre el archivo al cual referencia url que es de tipo
KURL (objeto para manejar una URL, por lo tanto, podemos abrir archivos locales o
a traves de protocolos como http, https, ftp, sftp, scp, smb, etc).
Tenemos las funciones para implementar drag and drop (arrastrar y soltar):
virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dropEvent(QDropEvent *event);
Cuando cerramos o abrimos la aplicación, esta guarda cierta configuración de
sesión (posición de la ventana, de las barras, etc), si nosotros necesitáramos guardar
(y recobrar) más información de sesión deberíamos hacerlo en las siguientes
funciones (que se encuentra implementadas en nuestra Prueba):
void saveProperties(KConfig *);
void readProperties(KConfig *);
KConfig es la clase de KDE utilizada para manejar archivos de configuración.
Para alguien que nunca programo utilizando Qt/KDE, lo siguiente, es sumamente
llamativo:
private slots:
esto indica que estas funciones son slots (ranuras) privados, no difieren mucho de
simples funciones privadas, excepto que para el sistema de signals/slots
(señales/ranuras) que provee Qt mediante moc estas funciones, son slots. Más
adelante se verá en detalle el funcionamiento de este sistema.
Las primeras funciones declaradas:
void fileNew();
void fileOpen();
void fileSave();
void fileSaveAs();
void filePrint();
void optionsShowToolbar();
void optionsShowStatusbar();
void optionsConfigureKeys();
void optionsConfigureToolbars();
void optionsPreferences();
son las correspondientes a las acciones de crear un nuevo archivo, de abrir un
archivo existente, de guardar un archivo, etc.
Las barras de herramientas de nuestra aplicación, van a ser configurables. Para
configurarlas vamos a usar el dialogo de configuración de barras de herramientas,
pero cuando la configuración cambie, la siguiente función:
newToolbarConfig();

José Pablo Ezequiel Fernández Página 8 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

es la que va a aplicar la configuración a la actual aplicación.


Las siguientes funciones sirven para cambiar el mensaje en la barra de estado y el
titulo de la ventana:
void changeStatusbar(const QString& text);
void changeCaption(const QString& text);
recordemos que el encargado de administrar la barra de estado y el titulo de la
ventana es la ventana principal, pero muy probablemente, el pedido para realizar
esos cambios venga de los widgets interiores.
QString es la clase provista por Qt para manejo de cadenas de caracteres.
setupAccel() y setupActions() son funciones que inicializan las aceleraciones de
teclado (o shortcut) y las acciones (abrir archivo, cerrar archivo, archivo nuevo,
quitar, ayuda, etc.), más detalles se verán a continuación.
Luego solo hay algunos punteros privados del cual el que más nos interesa es
Ejemplo1View *m_view; que es el puntero que va a ser usado por nuestro widget
principal.
El constructor de Ejemplo1 es bastante simple, lo más importante es que al principio
de todo crea un objeto m_view desde la clase Ejemplo1View. Uno de los parámetros
más importantes que tiene un widget es su padre y suele ser el primer parámetro de
la lista. El padre indica dentro de que widget va a estar el widget que creamos, el
padre de Ejemplo1 es el que se le pasa a KMainWindow como primer parámetro: 0.
Se le pasa ese valor, por que nuestra ventana principal, no esta adentro de ninguna
otra ventana, se dice que es una ventana de nivel superior. El widget m_view si
pertenece a otro widget, a nuestra ventana principal y por eso se le pasa this como
parámetro.
Para aceptar en nuestra aplicación, drag and drop (arrastrar y soltar), se hace la
siguiente llamada: setAcceptDrops(true);
setCentralWidget(m_view); hace que nuestro widget, sea el widget central. Esta es
una de las funciones que nos provee KMainWindow. Si no la usáramos, seria más
complejo.
Luego inicializamos las acciones (se vera más adelante): setupActions(), mostramos
la barra de estado: statusBar()->show(); (statusBar() es una función que nos provee
KMainWindow que nos devuelve un puntero al objeto de la barra de estado de la
ventana, pero como se puede ver, todavía no definimos ninguna barra de estado, eso
es, por que KMainWindow lo hace por nosotros) y le decimos a nuestra ventana
principal que guarde el tamaño, la posición, el tamaño de las barras de
herramientas, etc mediante setAutoSaveSettings() y que luego al abrir de nuevo el
programa, restablezca estos datos.
Las llamadas que siguen, son llamadas a la función connect() que es la que nos va a
permitir definir el funcionamiento asincrónico de nuestra aplicación como bien nos
explica la siguiente sección.

2.6 Conectando
Si lo pensamos desde un punto estricto de la programación orientada a objetos, los
widgets no son más que montones de objetos separados, entonces ¿Cómo se hace
para que un botón al ser presionado ejecute una función? o ¿Un item de menú cambie el
estado de otro item de menú?

José Pablo Ezequiel Fernández Página 9 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

Para resolver estos problemas, la biblioteca Qt nos provee con un sistema de signals
y slots (señales y ranuras) por las cuales un objeto puede tener una serie de signals
y una serie de slots y podemos interconectar cualquier signal con cualquier slot.
Como vimos anteriormente, un slot no es más que una función, que como cualquier
otra función puede ser privada, publica o protegida y hasta puede ser llamada
directamente, pero además, podemos conectar una señal para que la llame.
Las señales son emitidas cuando algo ocurre, por ejemplo un botón es presionado y
entonces emite la señal clicked() (presionado), si
nosotros conectamos (con la función connect()) esa
señal a nuestro slot llamado funcion1(), cada vez
que se presione el botón, nuestra función va a ser
ejecutada. Este sistema funciona gracias a moc.
Tanto el funcionamiento de moc, como la forma de
ejecutarlo escapan a este documento, KDevelop nos
provee todo lo necesario para no preocuparnos por
eso, solo debemos recordar, que cada objeto que
vaya a utilizar el sistema de signals/slots tiene que,
en su declaración, incluir la directiva Q_OBJECT y
en su implementación, incluir el archivo del mismo
nombre que si mismo, pero terminando en .moc,
para ejemplo1.cpp, el archivo a incluir es
ejemplo1.moc mediante: #include "ejemplo1.moc".
Figura 4: Cuatro objetos con
Viendo un ejemplo más complejo, la figura 4 nos varios slots y signals
muestra cuatro objetos Object1, Object2, Object3 y interconectados.
Object4 que vamos a suponer que son instancias de las clases Object1Class,
Object2Class, Object3Class y Object4Class respectivamente. El objeto Object1 tiene
su signal signal1 conectada al slot slot1 y a slot2 del objeto Object2 (una signal
puede estar conectada a más de un slot, así como más de una signal pueden estar
conectadas a un mismo slot) y el Object3 tiene su signal1 conectada al slot3 del
Object4, traduciéndolo en código, veríamos las declaraciones (simplificadas) como:
class Object1Class{
signals:
void signal1();
void signal2(int);
};
class Object2Class{
public slots:
void slot1();
void slot2();
signals:
void signal1();
};
class Object3Class{
public slots:
void slot1(char);
signals:
void signal1(double);

José Pablo Ezequiel Fernández Página 10 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

};
class Object4Class{
public slots:
void slot1(int);
void slot2();
void slot3(double);
};
y sus definiciones suponiendo que queramos que el slot slot1 de Object3 emita la
signal1:
void Object2Class::slot1(){
hacerAlgo();
}
void Object2Class::slot2(){
hacerAlgo();
}
void Object3Class::slot1(double x){
hacerAlgo(x);
emit signal1(43.5)
}
void Object4Class::slot1(int a){
hacerAlgo(a);
}

void Object4Class::slot2(){
hacerAlgo();
}
void Object4Class::slot3(double f){
hacerAlgo(f);
}
emit es una macro provista por Qt que debemos anteponer a las signals cuando las
queremos emitir.
Las definiciones de las signals no son necesarias, de hecho no deben estar ya que
son generadas por moc (en el archivo de extensión .moc, se verá más adelante).
Para generar las conexiones necesarias como indica la figura 4 deberíamos utilizar
el siguiente código:
connect(Object1, SIGNAL(signal1()), Object2, SLOT(slot1()));
connect(Object1, SIGNAL(signal1()), Object2, SLOT(slot2()));
connect(Object1, SIGNAL(signal2(int)), Object4, SLOT(slot1(int)));
connect(Object3, SIGNAL(signal1(double)), Object4, SLOT(slot3(double)));
SIGNAL y SLOT son macros que provee Qt que sirven para identificar signals y slots.
A tener en cuenta, es que para poder conectar una signal a un slot, estos deben
tener los mismos parámetros, seria imposible conectar Object1::signal1 a
Object4::slot1.

José Pablo Ezequiel Fernández Página 11 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

Volviendo a nuestra aplicación Ejemplo1, en el constructor de la clase Ejemplo1


podemos ver las siguientes conexiones:
connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)), this, SLOT
(changeStatusbar(const QString&)));
connect(m_view, SIGNAL(signalChangeCaption(const QString&)), this, SLOT
(changeCaption(const Qstring&)));
Estas conexiones hacen que, en el primer caso, la señal signalChangeStatusbar de
m_view (nuestro widget centra) llama a changeStatusbar, eso significa que en
cualquier momento, durante el funcionamiento de nuestra aplicación, adentro de
Ejemplo1View podemos emitir la señal signalChangeStatusbar y sin saber nada
sobre Ejemplo1 o KMainWindow o lo que sea (dentro de Ejemplo1View, por su
puesto) vamos a poder cambiar la barra de estado. Obviamente, esto depende de
que en Ejemplo1 se haga la conexión necesaria, podría existir el caso en el que no se
haga la conexión ya que no se necesita (supongamos que decidimos no usar barra de
estado, y por eso la quitamos de Ejemplo1, pero no tenemos razón para no darle a
Ejemplo1View la posibilidad de utilizar una barra de estado). La segunda conexión
es muy similar a la primera, pero para cambiar el titulo de la barra del programa.

2.7 Acciones, un objeto, muchas representaciones


En un programa tenemos una serie de acciones genéricas
que el usuario puede realizar. En nuestro Ejemplo1
tenemos:
• Archivo->Nuevo (File->New).
• Archivo->Abrir (File->Open).
• Archivo->Guardar (File->Save).
Figura 5: Menú Archivo o
• Archivo->Guardar Como... (File->Save As...). File
• Archivo->Imprimir... (File->Print...).
• Archivo->Quitar (File->Quit).
• Preferencias->Mostrar barra de herramientas
(Settings->Show Toolbar).
• Preferencias->Mostrar barra de estado (Settings-
>Show Statusbar).
Figura 6: Menú Preferencias
• Preferencias->Configurar accesos rápidos (Settings- o Settings
>Configure Shortcuts).
• Preferencias->Configurar barra de herramientas
(Settings->Configure Toolbars).
• Preferencias->Configurar Ejemplo1 (Settings-
>Configure Ejemplo1).
Figura 7: Menú Ayuda o
• Ayuda->Manual de Ejemplo1 (Help->Ejemplo1 Help
Handbook).
• Ayuda->¿Qué es esto? (Help->What's this?).

José Pablo Ezequiel Fernández Página 12 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

• Ayuda->Informar de fallo... (Help->Report Bug...).


• Ayuda->Acerca de Ejemplo1 (Help->About Ejemplo1).
• Ayuda->Acerca de KDE (Help->About KDE). Figura 8: Barra de
herramientas o Toolbar
Todas estas acciones están ordenadas como su
representación en el menú y hay una buena razón para eso, el menú es su
representación principal y no debería haber acción que no figure en el menú, pero
las acciones, también tienen otras representaciones, como botones en una barra de
herramientas, a veces, hay más de una barra de herramientas y en muchos casos
permitimos que el usuario configure las barras de herramientas (para que coloque
en ellas las herramientas que más usa). En el futuro puede que halla más
representaciones y que algunas desaparezcan, por eso fue importante encontrar una
solución genérica. Y así fue como KAction fue desarrollado.
KAction es una clase que encapsula una acción generada por el usuario y la
relaciona con un icono, con un texto, la función que lleva a cabo la acción en nuestro
programa. Esto evita problemas como que el icono en el menú y en la barra de
herramientas sea distinto, o su texto y su tooltip.
Cuando una KAction es ejecutada, por el método que sea emite una signal (activated
()) que simplemente debemos conectar a la función que lleva a cabo la acción y no
preocuparnos más. Cuando desactivemos la acción, KAction se va a encargar de
desactivarla en todas sus representaciones (en la barra de herramientas, en los
menús, etc). Y si por ejemplo, es del tipo de acción que se presiona una vez y se
activa y se presiona de nuevo y se desactiva (llamadas toggle en ingles), KAction
también se encarga que el estado de activación sea el mismo y el correcto en todos
los casos. Todo esto sumado nos ahorra tiempo al programar y mucho tiempo al
mantener la aplicación y tener menos fallos que resolver.
KAction es en realidad la clase madre de una serie que sirve para distintos tipos de
acciones:
• KSelectAction: Acción para seleccionar uno de varios items.
• KToggleAction: Acción para elegir por si o por no. Esta a su vez, tiene más
acciones:
• KRadioAction: Acción que opera como un botón radio.
• KToggleFullScreenAction: Acción para cambiar a modo pantalla completa.
• KToggleToolBarAction.html: Acción que se encarga de todo lo relacionado con
mostrar o ocultar barras de herramientas.
• KActionMenu: Acción utilizada para tener un sub-menú.
• KDataToolAction:Acción que ayuda a implementar soporte para KDataTool.
• KPasteTextAction: Acción para pegar texto desde el porta papeles.
• KToolBarPopupAction: Esta acción es una acción normal en cualquier lado,
excepto en una barra de herramientas, que tiene un menú desplegable.
• KWidgetAction: Acción que automáticamente inserta un widget adentro de la
barra de herramientas.
También es importante aclarar que hay un namespace llamado KStdAction que tiene
una serie de funciones para definir las acciones estandard, lo cual simplifica

José Pablo Ezequiel Fernández Página 13 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

realmente mucho el trabajo de crear menús. En el constructor se había llamado a la


función Ejemplo1::setupActions(); contiene el siguiente código:
KStdAction::openNew(this, SLOT(fileNew()), actionCollection());
KStdAction::open(this, SLOT(fileOpen()), actionCollection());
KStdAction::save(this, SLOT(fileSave()), actionCollection());
KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
KStdAction::print(this, SLOT(filePrint()), actionCollection());
KStdAction::quit(kapp, SLOT(quit()), actionCollection());
que crea, como podemos imaginar, las acciones para crear un nuevo archivo, abrir,
guardar, guardar como, imprimir y quitar respectivamente. También las conecta a
los slots fileNew(), fileOpen(), fileSave(), fileSaveAs(), filePrint() respectivamente, de
este mismo objeto (Ejemplo1), la ultima conexión es al slot quit() del objeto kapp
(kapp es un puntero al objeto KApplication que se creo en main.cpp).El tercer
parámetro es el KActionCollection, objeto que maneja un conjunto de KActions. Esta
es otra ventaja más de KMainWindow, crea el KActionCollection por nosotros y con
solo llamar a función actionCollection() nos devuelve un puntero a él.
Las siguientes dos lineas, son un poco distintas:
m_toolbarAction = KStdAction::showToolbar(this, SLOT(optionsShowToolbar()),
actionCollection());
m_statusbarAction = KStdAction::showStatusbar(this, SLOT
(optionsShowStatusbar()), actionCollection());
ya que estas acciones son de tipo toggle (eso significa, acciones por si o por no
presionables), necesitamos mantener un puntero a ellas, que van a ser
m_toolbarAction y m_statusbarAction que fueron declarados en ejemplo1.h. Con el
puntero, luego, sabremos si están presionados o no. Estas acciones son para mostrar
o esconder la barra de herramientas y lo mismo para la barra de estado.
Luego hay tres acciones más para la configuración de los accesos rápidos, de la
barra de herramientas y la configuración general:
KStdAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection
());
KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()),
actionCollection());
KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection
());
Por ultimo los desarrolladores de KDevelop nos muestran como crearíamos una
KAction que no sea estandard:
KAction *custom = new KAction(i18n("Cus&tom Menuitem"), 0, this, SLOT
(optionsPreferences()), actionCollection(), "custom_action");
Como podemos ver, no hay ninguna creación de las acciones del menú de ayuda, esa
parte es toda automática, después de todo, ¿Quién no quiere un menú de ayuda?
createGUI(), la ultima llamada, lleva a cabo la tarea más interesante relacionado con
las acciones. createGUI() lee un archivo XML con la definición de las barras de
herramientas y los menús y los genera. La definición especifica que menús y barras
existen y que acciones van a tener adentro. El archivo XML que se abre es un
archivo genérico que deberíamos proveer con nuestra aplicación, de hecho,
KDevelop ya nos genera uno: ejemplo1ui.rc pero si la aplicación encuentra el
archivo particular del usuario (~/.kde/share/apps/ejemplo1/ejemplo1ui.rc), en

José Pablo Ezequiel Fernández Página 14 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

cambio, utiliza este ultimo para construir la GUI. Esto


significa, que si modificamos el ejemplo1ui.rc,
podemos configurar las barras de herramientas y los
menús del usuario. Actualmente, ya hay un dialogo
(ventana especial) para hacer este trabajo.
Agregándole
KEditToolbar editToolbarDialog(actionCollection
());
connect(&editToolbarDialog,SIGNAL
(newToolbarConfig()),this,SLOT(newToolbarConfig
()));
editToolbarDialog.exec();
a la función Ejemplo1::optionsConfigureToolbars() (al Figura 9: Dialogo para
final de todo) tendremos funcionando el diálogo para configurar las barras de
edición de las barras de herramientas como lo herramientas de Ejemplo1
muestra la figura 9.

2.8 Nuestro widget Ejemplo1View


Nuestro widget interior es el que lleva el nombre de Ejemplo1View y es bastante
simple si bien realiza una tarea bastante compleja. Este widget es un navegador
web, o al menos, un interprete de HTML/XHTML pero trabaja simplemente cargando
el componente de interpretación HTML de KDE, llamado KHTML, que es el centro
de funcionamiento de Konqueror así como también Safari (el navegador web de
Apple). Explicar como lleva a cabo esta tarea en este momento no seria adecuado.
Lo que se puede destacar es que la clase Ejemplo1View declara dos signals
mediante el siguiente código:
signals:
/**
* Use this signal to change the content of the statusbar
*/
void signalChangeStatusbar(const QString& text);
/**
* Use this signal to change the content of the caption
*/
void signalChangeCaption(const QString& text);
La definición de signals es parecida a las de slots en el hecho de que usa una
palabra nueva, signals, pero como se puede ver, no son ni privadas, ni publicas, ni
protegidas, mientras los slots pueden llevar esas cualidades, las signals no (es como
si siempre fueran publicas.
Anteriormente vimos que Ejmplo1 (la clase) proveía dos slots para cambiar el texto
del titulo del programa y el texto de la barra de estado, estas son las signals que
emitiría nuestro widget interno, Ejemplo1View para llevar a cabo dichas acciones.
Estas funciones:
QString currentURL();
virtual void openURL(QString url);
virtual void openURL(const KURL& url);

José Pablo Ezequiel Fernández Página 15 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

son las que se usan para abrir una URL (o saber que URL esta abierta), estas son,
las funciones que llamaría la función Ejemplo1::fileOpen();
Ejemplo1View también hereda Ejemplo1Iface que tiene que ver con exportar
funciones con DCOP. Iface viene de la palabra en ingles interface (interfase en
español).
Este widget interno, no nos es realmente muy útil y lo más probable es que lo
reemplacemos casi en su totalidad. Podríamos simplemente, agregarle código para
que cree los botones, las listas des plegables, las etiquetas, etc que queramos, pero
eso es una tarea ardua y aca buscamos el camino más fácil y más corto, por eso,
vamos a usar Designer para esta tarea.

3 Diseñando GUIs con Designer


Designer es una muy útil herramienta desarrollada por TrollTech para llevar a cabo
el diseño de GUIs en forma WYSIWYG.
Designer puede hacer varios tipos de diálogos, widgets, wizards (diálogos para
llevar a cabo procesos paso a paso), ventanas principales (como nuestro Ejemplo1,
que es una ventana principal, pero usando QMainWindow en lugar de KMainWindow
para aplicaciones que solo usen las bibliotecas Qt y no las bibliotecas KDE), etc y
cuando lo abrimos, nos pregunta cual de ellos queremos fabricar. También vemos
tres tipos de archivos que no son widgets: C++ Project (Proyecto C++), C++ Source
File (Archivo de código fuente C++) y C++ Header File (Archivo de encabezado
C++). Estos archivos están aca ofreciendo las cualidades de IDE que ofrece
Designer hoy en día.

3.1 Creando un widget


Un widget, como se mencionó anteriormente puede tener, adentro, más widgets
como botones, listas de iconos, barras de desplazamiento, etc así es que creamos
widgets más complejos. Al principio puede ser un poco confuso que un widget pueda
ser un botón, o una serie de botones con barras de desplazamiento que controlan un
sistema de representación en tres dimensiones (Qt tiene una excelente integración
de OpenGL) del cerebro humano. Pero si lo miramos del aspecto exterior, va a ser
más fácil de entender: es necesario un componente que interactúe con el usuario
llevando a cabo ciertas tareas, desde las más
simples hasta las más complejas, siempre es un
componente que yo incluyo en un sector de la
pantalla, un widget.
Abrimos Designer y seleccionamos 'Widget' en el
diálogo de archivo nuevo (en caso de ser
necesario abrir este diálogo, se puede hacer
desde File->New).
Las barras de herramientas y las cajas de
herramientas pueden ser muy variadas depende
como esté configurado Designer pero más o Figura 10: Designer con un nuevo
menos debería ser como en la figura 10. La widget recién creado.
ventana del medio, que se ve en color gris, es
nuestro nuevo widget, listo para ser llenado de cajas de texto, grupos de botones y
todo lo que se nos ocurra.

José Pablo Ezequiel Fernández Página 16 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

A la izquierda vemos una caja de herramientas que tiene solapas, allí es donde
tenemos todos los posibles widgets que podemos poner en nuestro widget. Están
ordenados por categorías como Buttons (Botones), Containers (Contenedores), Views
(Vistas), etc. Los que dicen KDE en su descripción, son los widgets que provee KDE
el resto, suelen ser los que provee Qt. Arriba tenemos una barra de herramientas
con algunas funciones útiles y a la derecha tenemos (de arriba hacia abajo) la lista
de archivos abiertos (ordenada de acuerdo a los proyectos abiertos, en este caso,
ningún proyecto, solo un widget), la lista de objetos presentes en el widget
seleccionado, solo Form1 en este caso y por ultimo, la lista de propiedades del
objeto seleccionado que nos ofrece una gran variedad de cosas para cambiar, desde
el titulo, hasta el valor predeterminado, rango de valores, modo de funcionamiento,
margenes, separaciones, etc dependiendo de que tipo de widget sea.

3.2 Poniendo widgets en nuestro widget


Poner widgets en nuestro widget es tan simple como dibujar un rectángulo, tenemos
que elegir el widget, supongamos PushButton (botón de apretar) de Buttons
(botones), esto es para crear un QPushButton. Luego de seleccionarlo, sobre nuestro
widget (el de titulo Form1) hacemos click, arrastramos el puntero para darle el
tamaño que queríamos a nuestro widget y soltamos, nuestro botón esta listo.
Si seguimos probando con otros widgets, en
seguida podremos obtener algo como lo que se
ve en la figura 11.
En nuestro atestado widget podemos ver un
botón, un botón de herramienta, un botón
radio, un botón de chequeo, una caja de
herramientas con dos páginas, una caja de
agrupamiento, una caja de agrupamiento de
botones, tabulaciones, selección de archivos,
listas, listas por iconos, listas jerarquicas, un
botón de tecla, una regla, un selector de color,
un selector de grises, un selector de fecha, un
selector de fecha y hora, un selector de fecha
en calendario, un selector de tipografía y Figura 11: Widget con muchos otros
algunos más. Algunos de estos widgets son widgets adentro.
provistos por Qt, los más complejos, son
provistos por KDE.
Si observamos con detenimiento nuestro nuevo widget,
veremos que las cosas están muy mal ubicadas, hasta hay
cosas que levemente se enciman entre si, esto es por que
estos objetos fueron ubicados a mano y por consiguiente, con
error. Y si agrandamos o achicamos nuestro widget, veremos
resultados desastrosos como los muestran las figuras 12 y 13.

Figura 12: Nuestro


widget es demasiado
chico.

José Pablo Ezequiel Fernández Página 17 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

En la figura 12, nuestro widget fue achicado, dejando afuera


parte importante de datos y entrada, en cierto caso, podría
confundir terriblemente al usuario (la ventana por cuestiones
del escritorio puede haber sido creada muy chica y el usuario
podría no saber que hay más widgets).
En el segundo caso, en la figura 13, nuestro widget fue
agrandado, por que había lugar para hacerlo, pero los widgets
de adentro siguen ocupando el espacio inicial y si bien hay
widgets que necesitan más lugar o que podrían hacer buen Figura 13: nuestro
uso de mayor lugar, no lo están haciendo. widget es demasiado
Todos estos problemas se resuelven de una misma forma: grande.
creando layouts. Layouts se le llama a la serie de objetos que acomodan otros
objetos dentro de una ventana y que se encargan de utilizar el espacio lo mejor
posible (incluyendo el no permitir que la ventana sea achicada más de lo que debe).
Pero crear layouts, en especial, buenos layouts puede ser una tarea difícil y
agotadora.

3.3 Layouts, dinamismo a nuestra ventana


Hay tres tipos de layout, verticales, horizontales y de grilla.
Suponiendo que tenemos cuatro botones, para ordenarlos en
forma vertical, simplemente los colocamos en nuestro widget y
luego vamos al menú Layout donde seleccionamos, teniendo
nuestro widget Form1 seleccionado, Lay Out Vertically.
Obtendremos algo como en la figura 14. Si se agranda o se
achica esta ventana, los botones se agrandaran y se achicaran Figura 14: Botones
ordenados
con ella utilizando todo el espacio disponible y habrá un tope
verticalmente.
mínimo en el cual ya no se puede achicar más la ventana (por
que los botones empezarían a dejar de verse). Como existe un layout, no podemos
mover estos botones haciendo drag and drop, el layout los mantiene fijos en su
lugar, así que para rediseñar esta interfase, primero, tenemos que romper el layout.
Para romper el layout lo hacemos desde la opción: Layout->Break Layout (nota:
siempre que trabajamos con el layout de una ventana, la ventana tiene que estar
seleccionada, y no un objeto adentro de la ventana, como en este caso, un botón).
Creando un layout horizontal
obtendremos lo que se ve en la figura
15.
El layout de grilla es un poco más Figura 15: Botones ordenados horizontalmente.
complejo, ya que puede ser una grilla de dos casilleros por dos casilleros, o uno por
cuatro, o cuatro por uno y hasta tener casilleros vacíos o objetos que ocupen más de
un casillero. Lo más normal seria esperar un acomodamiento como el de la figura
16.
Cuando armamos una grilla, Designer 'adivina' como queremos
armar la grilla. Es una práctica normal, ubicar todos los
widgets y armar un layout grilla, deshacer la grilla (por que
Figura 16: Botones
Designer no dejo todo como nosotros lo queríamos), corregir lo en una grilla de dos
que esta mal, y volver a armar una grilla y repetir estas por dos.
acciones tantas veces como queríamos hasta que obtengamos
la GUI que queremos. Para nuestra simple interfase de cuatro botones, algunas
grillas posibles pueden ser:

José Pablo Ezequiel Fernández Página 18 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

Figura 17: Grilla de tres de


alto por dos de ancho
donde el botón 3 y 4 Figura 19: Grilla de 4 de
ocupan dos casilleros de Figura 18: Grilla de 3 de alto por alto por 2 de ancho con 4
ancho. 2 de ancho donde el botón 4 casilleros vacíos y 4 con
ocupa 3 casilleros de alto (nota: botones.
ciertas propiedades del botón 4
fueron cambiadas para que ocupe
todo el espacio disponible
verticalmente).

3.4 Widgets contenedores


Hay dos tipos de widgets, los que pueden tener
más widgets adentro y los que no. Cuando
creamos un widget o un diálogo con Designer
estamos trabajando sobre un widget que,
obviamente, puede tener widgets adentro. Pero
hay más widgets que pueden tener widgets en su
interior y se les llaman widgets contenedores o
containers en ingles. En la figura 20 podemos ver
los seis widgets contenedores que provee Qt (con
dos botones cada uno), que son QGroupBox, Figura 20: Widgets contenedores
QButtonGroup, QFrame, QTabWidget, provistos por Qt.
QWidgetStack y QToolBox.
Cada uno de estos widgets, tiene adentro, su propio layout para sus propios widgets
así como el widget exterior tiene su layout. En la figura 20, cada contenedor tiene
dos botones con un layout vertical como el usado en la figura 14.

3.5 Layouts avanzados


Inclusive cuando el layout de tipo grilla es muy versátil, puede que necesitamos, a
veces solo por comodidad, layout más complejos. Los layouts más complejos se
hacen poniendo layouts adentro de layouts. Hay dos métodos de creación de
creación de layouts:
• Asociado a un widget.
• Independiente.
El primero es el que ya vimos y que puede estar asociado al widget o diálogo que
estamos construyendo o a un widget contenedor. Para crear esos layouts
simplemente seleccionamos el widget sobre el cual queremos aplicar el layout y
seleccionamos el tipo de layout.
El layout independiente es el que forma una caja (vertical, horizontal o de grilla)
sobre un conjunto de widgets sin estar asociado al widget padre. Esto es útil cuando
queremos asociar grupos de widgets. Suponiendo una ventana que nos permita
agregar, borrar y modificar registros en una base de datos así como editarlos en la

José Pablo Ezequiel Fernández Página 19 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

misma ventana, tendríamos una serie de widgets en pares organizados en forma de


grilla (los pares campo/valor que seria una etiqueta “Nombre:” y un campo de
edición de texto donde escribir el nombre, otro par para apellido, etc) y abajo de
todo tendríamos tres botones “Agregar”, “Modificar”, “Borrar”. La primera parte va
bien ubicada en una grilla de dos lugares de ancho por los que hagan falta de alto,
mientras que los botones habría que ubicarlos en un layout horizontal, y todo junto,
en un layout vertical.
Para crear layouts independientes (específicos a un conjunto de widgets) tenemos
que seleccionar los widgets que queremos que estén en el layout y aplicar el layout.
Para crear el ejemplo antes mencionado, paso por paso, realizaríamos las siguientes
tareas:
1. Crear los widgets: Simplemente arrastrando y soltando creamos nuestros widgets
y luego modificamos las propiedades que hagan falta de acuerdo a nuestra
necesidad (ver figura 21).

Figura 21: Todos los


widgets en la ventana pero
ningún layout
2. Agregar un layout de grilla a los pares valor/campo: Para lograr esto
seleccionamos los widgets de nombre, la etiqueta y el campo, apellido, la etiqueta
y el campo, teléfono, la etiqueta y el campo. Luego de seleccionarlos vamos al
menú Layout y elegimos Lay Out in a Grid. Como se ve en la figura 22 alrededor
de los widgets que seleccionamos aparece un recuadro rojo que nos indica que
hay un layout. También podemos observar que los widgets se juntaron y achicaron
tanto como era posible.

Figura 22: Creado el


layout de grilla.
3. Agregar un layout horizontal a los botones: El proceso es el mismo, seleccionamos
los botones, vamos al menú Layout y elegimos Lay Out Horizontally. De nuevo
vemos que los widgets se juntaron y apareció un recuadro rojo.

José Pablo Ezequiel Fernández Página 20 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

Figura 23: Creado el layout


horizontal.
4. Crear layout general: y por último creamos un layout general, en el widget mismo
que va a manejar la disposición de los dos layouts creados en el punto 2 y 3 que
manejan la disposición de los widgets creados en el punto 1. Este layout va a ser
de tipo vertical ya que queremos los botones por debajo de los demás widgets. En
la figura 21 vemos como queda y en las figuras 25y 26 como queda cuando lo
ejecutamos. Como nos enseña la figura 26, a veces, Designer no es del todo
preciso y por eso siempre nos conviene probar nuestro widget, eso lo podemos
hacer desde el menú Preview.

Figura 25: Nuestra


ventana, como se vería
al ejecutar el
Figura 24: Layout general programa, en su
creado. tamaño más chico
posible.
Figura 26: Nuestra ventana, como se
vería al ejecutar el programa
maximizado.

3.6 Funciones, slots y signals en Designer


Designer nos permite agregar funciones, slots y signals a la clase del widget que
estamos creando.
En la ventana llamada Object Explorer (donde tenemos la lista de objetos creados)
tenemos una pestaña llamada Members. La cual nos permite declarar slots,
funciones, variables, signals, etc. También nos permite definir que archivos de
cabecera se incluirían en el código fuente generado posteriormente (ver la sección
3.8).
Para hacer una declaración tenemos que hacer doble click en donde la queremos
realizar y se abrirá una ventana que nos permite definir cada aspecto de la
declaración (parámetros, virtualidad, etc).

José Pablo Ezequiel Fernández Página 21 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

En la figura 27 podemos ver la ventana en la cual se


lleva a cabo la creación de una o más funciones.
Las funciones creadas se pueden implementar
utilizando Designer al hacer click sobre su nombre en
la pestaña Members o se puede implementar en una
subclase de la clase de nuestro widget. El segundo
método es el recomendado y es el que se verá en la Figura 27: Haciendo una
sección 3.8. declaración de una función
virtual publica
3.7 Conexiones en Designer
Designer también nos permite realizar las conexiones entre signals y slots que
haríamos si usáramos la función connect(). Para realizar esa tarea simplemente en
el menú Tools (Herramientas) seleccionamos la opción Connect Signals/Slots
(Conectar Signals/Slots). Esto va a ser que nuestro puntero se convierta en un cruz
la cual debemos posicionar sobre el widget que va a emitir la signal y hacer click.
Una ventana como la que se ve en
la figura 28 se abrirá, la cual tiene
cuatro columnas. En la primer
columna tenemos que seleccionar
(previamente seleccionado) el
objeto emisor y en la segunda cual
es el slot que queremos conectar.
En la tercera seleccionamos el
objeto receptor y en la cuarta en Figura 28: Creando una conexión.
que signal va a recibir la llamada.
Cuando hagamos la pre-visualización de nuestro widget estas conexiones estarán
vigentes y podremos ver como se comportan. Esta herramienta es muy útil si una
acción en la interfase cause un cambio inmediato en otro sector de la interfase, por
ejemplo: si una opción habilita a otro conjunto de opciones o si el movimiento del
cursor en una 'slider' tiene que reflejar su valor numérico en una etiqueta.

3.8 Integrando Designer en KDevelop


Esta tarea puede llevarse a cabo de muchas formas distintas, pero hay una que es la
más utilizada y para la cual KDevelop nos da ciertas herramientas.
Creando un nuevo proyecto como Ejemplo1, pero esta vez llamado Ejemplo2,
agregamos un widget creado por Designer de la siguiente forma:
1. Abrimos el Gestor de Automake (ubicado, generalmente, a la derecha).
2. Hacemos click derecho en nuestro target principal: ejemplo2 (programa en bin).
3. Elegimos crear nuevo archivo.
4. En el diálogo dejamos el directorio como está y elegimos el nombre, en este caso,
usaremos ABMWidget (Agregar, Borrar, Modificar, el conjunto de tareas
normalmente realizados sobre bases de datos). De la lista de tipos de archivos
seleccionamos Widget (.ui), ui es la extensión de los archivos de Designer
Agregamos el archivo aceptando ese diálogo y el siguiente.
Si bien el archivo .ui no es un archivo de código fuente como los .cpp y .h, el sistema
de scripts para automake que viene con KDE y que tiene nuestro proyecto esta
preparado para manejar archivos .ui. Los archivos .ui serán compilados por el

José Pablo Ezequiel Fernández Página 22 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

compilador uic (User Interface Compiler o Compilador de Interfase de Usuario) para


crear un archivo .cpp y un archivo .h con el código fuente que construye nuestro
widget. Para abrir nuestro recientemente creado widget, podemos hacer doble click
sobre el en el gestor de Automake, o abrirlo de
cualquier otra forma.
El método que vamos a usar para integrar nuestro
widget es el de crear una subclase o lo que es lo
mismo, una clase que hereda nuestro ABMWidget, y
esta clase, se va a llamar ABM. Es aconsejable en
nuestros proyectos siempre hacer esto, crear los
widgets con Designer con una palabra al final que los
identifique como son (Widget, Dlg, Dialog, View o lo
que elijamos) y luego la subclase, sin esa palabra, en
nuestro caso es ABMWidget y ABM. En la figura 29
vemos la ventana para crear las subclases, a ella se Figura 29: Creando una
accede desde el gestor de Automake, haciendo click subclase de ABMWidget,
derecho en nuestro widget (ABMWidget) y llamada ABM.
seleccionando Subclase widget...
Pero esto no hace que nuestro widget aparezca en ningún lugar de nuestro
programa y todavía requiere que a mano, en Ejemplo2View creemos un layout y una
instancia de ABM. Una forma de evitar esto seria crear un widget llamado
Ejemplo2ViewWidget y luego crear una subclase llamada Ejemplo2View (y así
estaríamos realizando nuestra interfase completa desde Designer. Antes debemos
borrar los archivos que componen Ejemplo2View: ejemplo2view.cpp y
ejemplo2view.h. Esto lo debemos hacer, también desde el gestor de Automake ya
que esto mantendrá actualizado los archivos de automake que son los que hacen
compilar nuestra aplicación.

4 Conclusión
El desarrollo rápido de aplicaciones utilizando herramientas libres en el entorno
Linux (u otro sistema libre como OpenBSD o FreeBSD) puede parecer intimidante ya
que no todo depende de una sola herramienta sino de una serie de herramientas que
hay que poner a trabajar en conjunto. No obstante es posible y es posible obtener
muy buenos resultados.

José Pablo Ezequiel Fernández Página 23 de 24


Desarrollo Rápido de Aplicaciones usando Qt/KDE y KDevelop

Índice de figuras
Figura 1: Creando un nuevo proyecto llamado Ejemplo1 con KDevelop.....................4
Figura 2: Ventana de compilación al empezar a compilar Ejemplo1...........................5
Figura 3: esta es nuestra aplicación, llamada Ejemplo1 ejecutándose por primera
vez................................................................................................................................5
Figura 4: Cuatro objetos con varios slots y signals interconectados..........................10
Figura 5: Menú Archivo o File....................................................................................12
Figura 6: Menú Preferencias o Settings.....................................................................12
Figura 7: Menú Ayuda o Help....................................................................................12
Figura 8: Barra de herramientas o Toolbar...............................................................13
Figura 9: Dialogo para configurar las barras de herramientas de Ejemplo1.............15
Figura 10: Designer con un nuevo widget recién creado...........................................16
Figura 11: Widget con muchos otros widgets adentro...............................................17
Figura 12: Nuestro widget es demasiado chico.........................................................17
Figura 13: nuestro widget es demasiado grande.......................................................18
Figura 14: Botones ordenados verticalmente.............................................................18
Figura 15: Botones ordenados horizontalmente........................................................18
Figura 16: Botones ordenados en una grilla..............................................................18
Figura 19: Grilla de tres de alto por dos de ancho donde el botón 3 y 4 ocupan dos
casilleros de ancho.....................................................................................................19
Figura 20: Grilla de 3 de alto por 2 de ancho donde el botón 4 ocupa 3 casilleros de
alto (nota: ciertas propiedades del botón 4 fueron cambiadas para que ocupe todo el
espacio disponible verticalmente)..............................................................................19
Figura 18: Grilla de 4 de alto por 2 de ancho con 4 casilleros vacíos y 4 con botones..
19
Figura 17: Botones en una grilla de dos por dos........................................................19
Figura 21: Widgets contenedores provistos por Qt....................................................19
Figura 22: Todos los widgets en la ventana pero ningún layout................................20
Figura 23: Creado el layout de grilla.........................................................................20
Figura 24: Creado el layout horizontal.......................................................................21
Figura 25: Layout general creado..............................................................................21
Figura 26: Nuestra ventana, como se vería al ejecutar el programa, en su tamaño
más chico posible.......................................................................................................21
Figura 27: Nuestra ventana, como se vería al ejecutar el programa maximizado.....21
Figura 28: Haciendo una declaración de una función virtual publica.......................22
Figura 29: Creando una conexión..............................................................................22
Figura 30: Creando una subclase de ABMWidget, llamada ABM..............................23
La figura 4 (en la página 10) tiene copyright (derechos de autor) de TrollTech y
puede ser encontrada en su formato original en
http://www.trolltech.com/products/qt/whitepaper/abstract-connections.png. La
imagen fue modificada para este documento.

José Pablo Ezequiel Fernández Página 24 de 24

También podría gustarte