Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Documentacion QT
Documentacion QT
Curso 2007/08
ndice general
ndice General
1. Introduccin al uso de Qt
1.1. Qu es Qt? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
11
11
1.4.2. Un ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.5. Qt y OpenGL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
15
17
18
19
19
22
22
1.5.8. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
c
F.J. Melero
Captulo 1
Introduccin al uso de Qt
1.1.
Qu es Qt?
Es una librera para desarrollar aplicaciones con interfaz grfico de usuario con C++.
En realidad, como todo software que se precie, no son slo unas clases empaquetadas y
listas para enlazar con ellas en tiempo de compilacin, sino que Qt proporciona una serie
de herramientas y documentacin imprescindibles para el desarrollador:
Qt Designer, para crear dilogos e interfaces grficamente (echadle un vistazo, es
bastante bueno),
Qt Linguist, una herramienta para crear aplicaciones multilinges
Qt Assistant, un generador de documentacin
qmake, un generador de Makefiles multiplataforma.
Las aplicaciones ms populares que usan Qt son por supuesto las de KDE. Las libreras
de KDE extienden y complementan a las de Qt, as que las aplicaciones KDE dependen
de Qt. Hay otras aplicaciones interesantes hechas con Qt, pero que no son KDE. Las ms
populares son Scribus, Skype y muchas otras.
Introduccin al uso de Qt
1.1.1.
1.1.2.
% cd /tmp
% gunzip qt-x11-opensource-src-4.3.3.tar.gz
% tar xvf qt-x11-opensource-src-4.3.3.tar
Esto crear el directorio /tmp/qt-x11-opensource-src-4.3.3 con los archivos necesarios.
2. Compilacin e instalacin
%
%
%
%
cd /tmp/qt-x11-opensource-src-4.3.3
./configure
make
su -c "make install"
Ntese que la ltima lnea est solicitando ejecutar make install como root, para
poder alojar las libreras en /usr/local/Trolltech/Qt-4.3.3. Obviamente, nos
pedir contrasea.
Podemos pedirle que se instalen en otra ruta indicando con -prefix la ruta deseada: sudo
-c "make install -prefix /ruta/deseada"
3. Configuracin de las variables del sistema.
En el archivo /.profile (si la shell es bash, ksh, zsh o sh), hay que aadir:
PATH=/usr/local/Trolltech/Qt-4.3.3/bin:$PATH
export PATH
En ~/.login (si la shell es csh o tcsh), se aade la siguiente lnea
setenv PATH /usr/local/Trolltech/Qt-4.3.3/bin:$PATH
En las aulas de prcticas puede ser necesario extender la variable de entorno
LD_LIBRARY_PATH incluyendo la ruta /usr/local/Trolltech/Qt-4.3.3/lib.
1.2.
Hola Mundo
Como todo en informtica, hay que empezar con el "Hola Mundo". Se trata de realizar
un programa mnimo que tan slo saque por pantalla la famosa frase.
He aqu el cdigo
#include <QApplication>
#include <QLabel>
int main (int argc, char *argv[]) {
QApplication app(argc,argv);
QLabel *etiqueta = new QLabel ("Hola Mundo");
etiqueta->show();
return app.exec();
}
c
F.J. Melero
Introduccin al uso de Qt
1.2.1.
Lnea a lnea
#include <QApplication>
Incluimos la definicin de la clase QApplication. Debe haber uno y slo un objeto
QApplication en cada programa que haga uso de un interfaz grfico con Qt. La clase
QApplication gestiona temas tales como el cursor del ratn, la fuente por defecto, etc...
#include <QLabel>
Incluimos la definicin de la clase QLabel. Todas las clases de Qt comienzan con la letra
Q, y para cada clase de la API, hay un fichero .h con el mismo nombre que contiene su
definicin. Al ser C++, no es necesario poner la extensin.
QLabel es un componente visual que sirve para mostrar texto esttico, es decir, que
el usuario no puede modificar el contenido. Tiene sus propias propiedades (color de fondo,
tamao de la fuente, dimensiones, etc...) como cualquier otro componente (widget) de la
librera.
int main(int argc, char *argv[])
Como cualquier programa en C++, todo comienza con el main(). En la mayora de
los casos, el main() slo tiene que realizar un par de operaciones de inicializacin antes de
pasar el control a la librera Qt, que es quien se encarga de detectar y gestionar las acciones
del usuario mediante eventos.
QApplication app(argc, argv);
El objeto app es la instancia de la QApplication. Se crea aqu. Los argumentos
sirven para pasar opciones desde lnea de comandos, pero raramente se usan.
Debe ser la primera lnea del main, o al menos, la primera en la que se haga referencia
a algn elemento Qt.
QLabel *etiqueta= new QLabel("Hola Mundo");
Creamos un objeto etiqueta, QLabel. El argumento del constructor es el texto que se
va a mostrar. Como no le hemos indicado ninguna ventana como elemento padre (sera el
segundo argumento), el componente en s se comportar como una ventana, con barra de
ttulo, marco, etc...
etiqueta->show();
Hay que distinguir entre la creacin de componentes y su visibilidad. En la lnea anterior
hemos creado el objeto QLabel, pero ese objeto est en memoria. En ningn momento se
le ha dicho que se visualice. Por eso se ejecuta el mtodo show(), para hacerlo visible.
return app.exec();
}
Aqu es cuando el main pasa el control a Qt. QCoreApplication::exec() acabar cuando se finalice la aplicacin.
En QCoreApplication::exec(), Qt recibe y procesa los eventos del usuario y
del sistema, y se encarga de gestionar la respuesta a stos segn lo que el programador haya
determinado.
c
F.J. Melero
1.2.2.
Compilacin y ejecucin
1.3.
Algo ms complejo
Vamos a introducir el concepto de los eventos de usuario. Para ello crearemos una ventana con un botn que, al pulsarlo, finalizar la ejecucin:
#include
#include
#include
#include
#include
<QApplication>
<QFont>
<QPushButton>
<QLabel>
<QWidget>
c
F.J. Melero
10
Introduccin al uso de Qt
1.3.1.
Lnea a lnea
#include <QWidget>
Incluimos la clase base de todos los componentes de Qt, <QWidget>.
QWidget window;
Se crea un componente bsico, que va a ser utilizado como contenedor de todos los dems.
Un componente que no es incluido en otros se denomina ventana. Se podra decir que los
componentes o widgets son los ladrillos del interfaz de usuario: reciben los eventos de ratn
y teclado, las seales del sistema, son los encargados de pintar la interfaz grfica... Adems,
un componente es recortado por su padre y por los que se superponen a l.
Si no se especifica otra cosa, es el gestor de ventanas quien se encarga de colocar la
ventana de nuestra aplicacin en un lugar del escritorio.
window.resize(200, 120);
Definimos la ventana con 200 pxeles de ancho y 120 de alto.
QLabel etiqueta("Pulse para salir", &window);
QPushButton salir("Salir", &window);
Creamos dos componentes: una etiqueta y un botn. Tanto la etiqueta, QLabel, como el
botn, de la clase QPushButton, se crean con un segundo parmetro que es su componente padre (window). Un componente hijo siempre se visualiza dentro del rea ocupada
por su ancestro y es recortado si excede de sus lmites. Por defecto, se localiza en la esquina superior izquierda de su elemento contenedor, en la posicin (0,0). En este ejemplo, la
etiqueta queda en dicha posicin.
salir.setFont(QFont("Times", 18, QFont::Bold));
Establecemos para el botn el tipo y tamao de la fuente. Para ello, se usa el mtodo
QWidget::setFont(QFont) que recibe como parmetro un objeto del tipo QFont.
ste objeto es creado con tres parmetros: la familia de la fuente ("Times"), el tamao (18)
y el estilo (Qfont::Bold).
salir.setGeometry(10, 40, 180, 40);
c
F.J. Melero
11
1.4.
Gestin de eventos en Qt
1.4.1.
Seales y slots
12
Introduccin al uso de Qt
1.4.2.
Un ejemplo
13
int m_value;
};
La podemos convertir en un objeto Qt aadiendo unas pocas lneas de cdigo:
#include <QObject>
class Contador : public QObject {
Q_OBJECT
public:
Contador() { m_value = 0; }
int value() const { return m_value; }
public slots:
void setValue(int value);
signals:
void valueChanged(int newValue);
private:
int m_value;
};
La idea es la misma, y los metodos pblicos son los mismos, pero le hemos aadido la
propiedad de responder a eventos mediante seales y slots. Esta clase le cuenta al mundo
exterior que su estado ha cambiado emitiendo la seal valueChanged(), y tiene un slot
al que otros objetos podran enviar seales.
Importante: Todas las clases que definan seales o slots deben incluir Q_OBJECT al
principio de su declaracin, y deben derivar -directa o indirectamente- de QObject.
Los slots son implementados por el programador. He aqu una posible implementacin
del slot Contador::setValue():
void Contador::setValue(int value)
{
if (value != m_value) {
m_value = value;
emit valueChanged(value);
}
}
La segunda lnea del if emite la seal valueChanged() con el nuevo valor como
argumento.
En el siguiente trozo de cdigo, creamos dos objetos Contador y conectamos la seal
valueChanged() del primero al setValue() del segundo, usando
QObject::connect():
Contador a, b;
c
F.J. Melero
14
Introduccin al uso de Qt
QObject::connect(&a, SIGNAL(valueChanged(int)),
&b, SLOT(setValue(int)));
a.setValue(12);
b.setValue(48);
1.5.
Qt y OpenGL
Vamos a crear un esqueleto potente para poder desarrollar todas las prcticas de la asignatura. El ncleo del interfaz del usuario son dos clases: la Ventana y el VisorOpenGL.
Vamos a ver la estructura del cdigo de forma jerrquica, empezando por el main:
#include <QApplication>
#include "ventana.h"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Ventana ventana;
ventana.show();
return app.exec();
}
Lo primero que llama la atencin es que no usamos ni QWidget, ni QLabel ni nada,
slo Ventana. Es una forma de aislar completamente la ejecucin y tener bien localizados
todos los componentes. He aqu el archivo ventana.h:
#ifndef VENTANA_H
#define VENTANA_H
#include <QWidget>
c
F.J. Melero
1.5 Qt y OpenGL
15
#include "visoropengl.h"
class Ventana : public QWidget {
Q_OBJECT
public:
Ventana();
private:
VisorOpenGL *visorOpenGL;
};
#endif
Podemos ver como la Ventana no es ms que un QWidget modificado. En el constructor realizamos todas las operaciones de creacin de componentes y organizacin de los
mismos:
#include <QtGui>
#include "visoropengl.h"
#include "ventana.h"
Ventana::Ventana() {
visorOpenGL = new VisorOpenGL;
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(visorOpenGL);
setLayout(mainLayout);
setVentanaTitle(tr("Informtica Grfica.
Pepito Prez Prez"));
}
1.5.1.
Definicin de VisorOpenGL
<QGLWidget>
<QEvent>
<QMouseEvent>
"escena.h"
16
Introduccin al uso de Qt
~VisorOpenGL();
QSize minimumSizeHint() const;
QSize sizeHint() const;
public slots:
void setXRotation(float angle);
void setYRotation(float angle);
void setZRotation(int angle);
signals:
void xRotationChanged(float angle);
void yRotationChanged(float angle);
void zRotationChanged(int angle);
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
void setObserver();
void setProjection();
void dibujarEscena();
private:
QPoint lastPos;
Escena escena;
GLint Draw_type;
int
int
int
int
Window_width;
Window_height;
Front_plane;
Back_plane;
float
float
float
float
Observer_distance;
observer_angle_x;
observer_angle_y;
observer_angle_z;
1.5 Qt y OpenGL
17
Las seales y slots se usan para permitir a otros objetos interactuar con la escena 3D.
La inicializaciin de OpenGL, la redimensin del viewport, y el dibujado de la escena
se realizan reimplementando las funciones QGLWidget::initializeGL(),
QGLWidget::resizeGL(), y QGLWidget::paintGL(). Para permitir al usuario
interactuar directamente con la escena usando el ratn, reimplementamos
QWidget::mousePressEvent() y QWidget::mouseMoveEvent(), y para interactuar con el teclado reimplementamos QWidget::keyPressEvent().
El resto de la clase contiene funciones y variables tiles para construir y manipular la
escena.
1.5.2.
Implementacin de VisorOpenGL
18
Introduccin al uso de Qt
Las dos siguientes funciones sirven para controlar de alguna forma que el componente
se visualiza con unas dimensiones adecuadas. Definimos las dimensiones mnimas y las
ptimas.
QSize VisorOpenGL::minimumSizeHint() const {
return QSize(50, 50);
}
QSize VisorOpenGL::sizeHint() const {
return QSize(400, 400);
}
El visor proporciona tres slots que permiten a otros componentes cambiar la orientacin
de la escena:
void VisorOpenGL::setXRotation(int angle) {
normalizeAngle(&angle);
if (angle != xRot) {
xRot = angle;
emit xRotationChanged(angle);
updateGL();
}
}
Ntese que la variable xRot slo se actualiza si el ngulo nuevo es diferente al antiguo.
Entonces, se emite la seal xRotationChanged() de forma que otros componentes
puedan actualizarse y se llama al mtodo updateGL(), ya existente por defecto en el
componente.
Los mtodos setYRotation() y setZRotation() realizan la tarea anloga para los otros ejes.
1.5.3.
Inicializacin de OpenGL
Independientemente del sistema gestor de ventanas y de interfaz de usuario que utilicemos, es necesario realizar una tarea de inicializacin del motor de OpenGL, previamente a
cualquier operacin de dibujado. Normalmente estas tareas estn relacionadas con la definicin de colores, materiales, habilitacin de caracteristicas (doble buffer, zbuffer, etc...) y
otras propiedades del proceso de dibujado.
void VisorOpenGL::initializeGL() {
glClearColor(1.0,1.0,1.0,1.0);
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}
Podemos ver como se ha definido un color de fondo (blanco), y se ha definido que el
sombreado sea plano. Adems, se habilita el test de profundidad y la deteccin de caras
ocultas.
c
F.J. Melero
1.5 Qt y OpenGL
1.5.4.
19
1.5.5.
Dibujando la escena
La funcin paintGL() se usa para pintar los contenidos de la escena en el componente. En nuestro caso, como slo vamos a hacer uso de OpenGL para dibujar, reimplementamos la funcin QGLWidget::paintGL() en lugar de la bsica
QWidget::paintEvent():
void VisorOpenGL::setObserver(){
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0,0,-Observer_distance);
glRotatef(observer_angle_x,1,0,0);
glRotatef(observer_angle_y,0,1,0);
}
void VisorOpenGL::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
setProjection();
setObserver();
dibujarEscena();
c
F.J. Melero
20
Introduccin al uso de Qt
}
Podemos ver como lo primero que hacemos es borrar el color de fondo (definido en
initializeGL() ) y limpiamos el zbuffer.
A continuacin, invocamos la funcin setObserver() que se encarga de aplicar las
transformaciones necesarias para que la escena sea visible desde donde deseamos.
Finalmente, llamamos a un mtodo que se encarga de dibujar la escena, invocando al
mtodo dibujarEscena(). En principio se podra incluir el cdigo de dibujado en esta
misma funcin, pero lo hemos separado para que queden ms claras las distintas etapas que
intervienen en el dibujado de una escena OpenGL:
void VisorOpenGL::dibujarEscena() {
this->escena.draw();
}
En nuestro objeto VisorOpenGL tenemos un elemento Escena, que es el que se
encargar de organizar todos los elementos a dibujar.
La Escena
La escena, en el ejemplo que proporcionamos, se basa en unos ejes de coordenadas
(encapsulados en la clase Axis) y ocho puntos que sern conectados de forma distinta
segn las primitivas grficas que decidamos. Para la mayora de la prcticas de la asignatura,
sta es la nica clase de las proporcionadas en el ejemplo que tendremos que modificar (ello
no quita que habr que aadir ms).
La definicin de la escena (escena.h) es:
#ifndef ESCENA_H
#define ESCENA_H
#include "axis.h"
class Escena {
private:
Axis ejes;
GLuint Draw_type;
GLfloat vertices[8][3];
public:
Escena();
void setDrawType(GLuint drawtype);
void draw();
};
#endif
De toda la clase, aparte del constructor que se puede consultar en el cdigo proporcionado, lo ms interesante es la funcin de dibujado. Ntese como no hay ningn tipo de cdigo
referente al observador o a las transformaciones de vista, sino simplemente el dibujado de
los elementos que queremos que aparezcan:
c
F.J. Melero
1.5 Qt y OpenGL
21
void Escena::draw(){
ejes.draw();
glColor3f(0.0,0.0,0.0);
glPointSize(4);
switch (Draw_type){
case GL_POINTS:
glBegin(GL_POINTS);
break;
case GL_LINES:
glBegin(GL_LINES);
break;
case GL_LINE_STRIP: glBegin(GL_LINE_STRIP);
break;
case GL_LINE_LOOP: glBegin(GL_LINE_LOOP);
break;
case GL_POLYGON:
glBegin(GL_POLYGON);
break;
case GL_QUADS:
glBegin(GL_QUADS);
break;
case GL_QUAD_STRIP: glBegin(GL_QUAD_STRIP);
break;
case GL_TRIANGLES: glBegin(GL_TRIANGLES);
break;
case GL_TRIANGLE_STRIP: glBegin(GL_TRIANGLE_STRIP);
break;
case GL_TRIANGLE_FAN:
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0,0,0);
break;
}
for (int i=0;i<8;i++){
glVertex3fv((GLfloat *) &vertices[i]);
}
glEnd();
}
c
F.J. Melero
22
Introduccin al uso de Qt
1.5.6.
Tal y como se hace con las subclases de los componentes nativos, los eventos de ratn se
gestionan reimplementando funciones tales como QWidget::mousePressEvent() y
QWidget::mouseMoveEvent().
La funcin mousePressEvent(), en nuestro caso, se va a encargar slo de almacenar la posicin del cursor del ratn en el momento en que hacemos clic.
void VisorOpenGL::mousePressEvent(QMouseEvent *event) {
lastPos = event->pos();
}
La funcin mouseMoveEvent() usa la localizacin anterior del cursor para determinar cunto debe rotarse el objeto, y en qu direccin. Por ahora slo vamos a permitir la
rotacin en los ejes X e Y.
void VisorOpenGL::mouseMoveEvent(QMouseEvent *event)
int dx = event->x() - lastPos.x();
int dy = event->y() - lastPos.y();
1.5.7.
{
setYRotation(++observer_angle_y);
break;
case Qt::Key_Left:
setYRotation(--observer_angle_y);
break;
case Qt::Key_Up:
setXRotation(--observer_angle_x);
break;
case Qt::Key_Down:
setXRotation(++observer_angle_x);
break;
case Qt::Key_PageUp:
Observer_distance*=1.2;break;
case Qt::Key_PageDown: Observer_distance/=1.2;break;
// Primitivas Grficas
case Qt::Key_F1: Draw_type=GL_POINTS;break;
case Qt::Key_F2: Draw_type=GL_LINES;break;
case Qt::Key_F3: Draw_type=GL_LINE_STRIP;break;
c
F.J. Melero
1.5 Qt y OpenGL
23
1.5.8.
Resumen
Hemos visto cmo realizar una especializacin de la clase QGLWidget para tener
un visor donde poder pintar escenas con OpenGL. Al ser QGLWidget una subclase de
QWidget, todas sus derivadas se puecen colocar en paneles y se puede interactuar con
ellas como con cualquier otro componente.
Para asegurarnos de que el visor pinta correctamente la escena, hay que reimplementar
al menos las siguientes funciones:
QGLWidget::initializeGL(), que inicializa los recursos de OpenGL.
QGLWidget::resizeGL(), que controla las variaciones de tamao del visor y
ajusta el viewport a las dimensiones adecuadas, calculando la nueva transformacin
de vista.
QGLWidget::paintGL(), que se encarga de realizar las llamadas OpenGL para
su visualizacin.
Importante: En el archivo de proyecto .pro hay que aadir la siguiente lnea para que
compile con las cabeceras y libreras especficas para OpenGL:
QT += opengl
c
F.J. Melero
24
c
F.J. Melero
Introduccin al uso de Qt
Bibliografa
[1] Qt Reference Documentation (Open Source Edition),
http://doc.trolltech.com/4.3/
[2] Completo tutorial online de OpenGL con Qt.
http://www.digitalfanatics.org/projects/qt_tutorial
/chapter14.html
[3] Web oficial del OpenGL consortium http://www.opengl.org
[4] J. Blanchette y M. Summerfield, C++ GUI Programming with Qt 4, 2nd
Edition, Prentice Hall, 2008 (Versin online desde la biblioteca en Safari:
http://safari.oreilly.com/9780137143979 )
c
F.J. Melero