Zona Qt: Nuevo sitio web dedicado a Qt

PésimoMaloRegularBuenoExcelente (No Ratings Yet)
Loading ... Loading ...

Este post es sólo para informarles que he estado colaborando con Alfredo Castañeda, el creador del foro Qt en Español, para crear un nuevo sitio web dedicado a Qt, llamado Zona Qt, y al cuál los invito a registrarse.

Registrate en Zona Qt

Registrarse en el nuevo sitio tiene muchas ventajas si su principal interés es el desarrollo con Qt. Dichas ventajas son:

  • Habrá foro de discusión: Probablemente la inclusión más importante y necesaria. Podrás publicar conocer y conversar directamente con otros usuarios de Qt que te podrán ayudar a resolver dudas y problemar, gracias al foro anterior de Alfredo el foro no empieza vacío, si no que contaremos con la participación de sus 62 usuarios registrados.
  • Publicación de Noticias: Traducción de noticias oficiales de los desarrolladores de Qt y publicación de otras noticias relacionadas como realización de eventos o revisión de aplicaciones.
  • Tutoriales, Howtos y Videotutoriales: Migración y adaptación del tutorial de Qt de este sitio y publicación de nuevos howtos y videotutoriales.
  • Galería de proyectos: Los usuarios del sitio tienen la posibilidad de compartir sus proyectos en el sitio con el fin de buscar colaboradores u opiniones y de mostrar todo lo que se puede hacer con Qt.

Registrate en Zona Qt

Espero que les interese la idea y que se registren pronto en el nuevo sitio. Saludos.

Bienvenido a Programación en Linux

PésimoMaloRegularBuenoExcelente (4 votes, average: 4.75 out of 5)
Loading ... Loading ...

El objetivo de este sitio es proporcionar material de aprendizaje para la programación en GNU/Linux, la diferencia de este sitio con otros es que aquí intentaremos que todo el contenido que generemos o enlacemos sea en Español debido a la relativa escasez de este tipo de material en nuestro idioma y a las dificultades que esto trae consigo, además, en un futuro cercano proporcionaremos un sitio “inteligente” de preguntas y respuestas fuertemente inspirado en el sitio estadounidense Stack Overflow, y que intentará ser completamente diferente en calidad a sitios como Yahoo! Respuestas.

Si deseas saber más sobre el sitio o los autores consulta la sección Acerca de.

El sitio aún se encuentra “en construcción” por lo tanto el material con el que cuenta aún es escaso. Los temas que hemos tratado son:

Tutorial de Qt 4: Item/View Widgets, mostrar conjuntos de datos de manera sencilla (Parte I)

PésimoMaloRegularBuenoExcelente (2 votes, average: 5.00 out of 5)
Loading ... Loading ...

En la parte anterior de este tutorial vimos como utilizar los diálogos estándar que Qt nos ofrece para realizar tareas comunes de interacción con el usuario, como solicitar confirmación para realizar acciones o informar del estado de una acción.

En este artículo revisaremos las características principales de las clases de conveniencia del framework “Model/View Programming” que nos ofrece Qt y revisaremos a detalle uno de los Item/View Widgets, el QListWidget.

Los widgets que revisaremos en este artículo forman parte de un framework dentro de Qt conocido como Item/View Programming. Este framework nos sirve para mostrar al usuario conjuntos de datos, conocidos como modelos de datos, que provengan de diversas fuentes como archivos de texto, bases de datos o la web. Dicho framework provee una arquitectura Modelo/Vista la cual es una ligera variación del patrón de diseño Modelo Vista Controlador (MVC) el cuál es un patrón muy popular en aplicaciones web, o en otras aplicaciones, generalmente grandes o complejas. Este patrón ofrece importantes beneficios en cuanto a rendimiento y mantenibilidad de la aplicación pero implementarlo tiene cierta complejidad para la cual probablemente no valga la pena atravesar en el caso de una aplicación sencilla o pequeña. Para casos como este, Qt provee los widgets “de conveniencia” que veremos en este artículo.

Comenzaremos por revisar el QLisWidgetItem, el cual es un widget que nos permite mostrar una un conjunto elementos en forma de lista y nos ofrece métodos para insertar y eliminar dichos elementos.

Usaremos una pequeña aplicación pare ejemplificar el uso de este widget, esta aplicación será una lista de compras o tareas, en la que podemos agregar, quitar y marcar productos como comprados. Cada que agreguemos un elemento a la lista, lo colocaremos en la parte superior de ella, dispondremos de una checkbox en cada elemento para indicar si ya fue comprado/completado o no, al marcar esta checkbox moveremos este producto al final de la lista y lo coloreamos de gris con el fin de que la atención se centre en los elementos restantes. Si nos equivocamos al agregar un elemento o decidimos que ya no lo queremos en la lista, simplemente lo seleccionamos y presionamos el botón eliminar.

Nuestro proyecto se compone de tres archivos:

  • Lista.h Contiene la definición de la clase que representa al widget de nuestra lista
  • Lista.cpp Contiene la implementación de la clase que representa al widget de nuestra lista
  • main.cpp

A continuación mostramos y explicamos el código de los archivos que componen nuestra aplicación

NOTA: Sólo explicaremos el código relevante al tema de este tutorial o que no haya sido explicado antes en este tutorial.

El código del archivo ListaDeCompras.h es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef LISTADECOMPRAS_H
#define LISTADECOMPRAS_H
 
#include <QWidget>
#include <QObject>
 
class QListWidget;
class QPushButton;
class QListWidgetItem;
 
class ListaDeCompras : public QWidget
{
	Q_OBJECT
 
public:
    ListaDeCompras();
private:
	QListWidget* lista;
	QPushButton* botonAgregar;
	QPushButton* botonQuitar;
private slots:
	void botonAgregarPresionado();
	void botonQuitarPresionado();
	void productoMarcado(QListWidgetItem *);
};
 
#endif // LISTADECOMPRAS_H

De las líneas 4 a 9 incluimos los archivos de cabecera y definiciones de clases que utilizaremos en este ejemplo.

En la línea 11 comienza la definición de nuestra clase, de las líneas 18 a 20 declaramos los widgets que utilizaremos, en este caso sólo utilizaremos la lista y dos botones que nos permitan agregar y quitar elementos, respectivamente.

De las líneas 22 a 24 declaramos los slots que proveerán la funcionalidad de nuestra aplicación. Definimos un slot que conectamos a la señal emitida por cada botón y uno que se conecta a la señal que emite la lista cuando modificamos un elemento de ella, en este caso cuando marcamos o desmarcamos la casilla que indica que el elemento ha sido comprado/completado.

El código del archivo ListaDeCompras.cpp es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "listadecompras.h"
#include <QListWidget>
#include <QListWidgetItem>
#include <QPushButton>
#include <QInputDialog>
#include <QMessageBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
 
ListaDeCompras::ListaDeCompras()
{
	QHBoxLayout* layoutPrincipal = new QHBoxLayout;
	QVBoxLayout* layoutBotones = new QVBoxLayout;
 
	lista = new QListWidget;
	botonAgregar = new QPushButton(trUtf8("Agregar"));
	botonQuitar = new QPushButton(trUtf8("Quitar"));
 
	layoutBotones->addWidget(botonAgregar);
	layoutBotones->addWidget(botonQuitar);
	layoutBotones->addStretch();
 
	layoutPrincipal->addWidget(lista);
	layoutPrincipal->addLayout(layoutBotones);
 
	setLayout(layoutPrincipal);
 
	connect(botonAgregar, SIGNAL(clicked()), this, SLOT(botonAgregarPresionado()));
	connect(botonQuitar, SIGNAL(clicked()), this, SLOT(botonQuitarPresionado()));
	connect(lista, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(productoMarcado(QListWidgetItem*)));
}
 
void ListaDeCompras::botonAgregarPresionado()
{
	QString nombreNuevoProducto = QInputDialog::getText(this, trUtf8("Lista de Compras"), trUtf8("Producto:"));
 
	if(nombreNuevoProducto.trimmed() == "") {
		QMessageBox::warning(this, trUtf8("Lista de Compras"), trUtf8("Debe indicar el nombre del producto"));
		return;
	}
 
	for(int i=0; i<lista->count(); i++) {
		if(nombreNuevoProducto == lista->item(i)->text()) {
			QMessageBox::warning(this, trUtf8("Lista de Compras"), trUtf8("Ya existe un producto con ese nombre"));
			return;
		}
	}
 
	QListWidgetItem* nuevoProducto = new QListWidgetItem(nombreNuevoProducto);
	nuevoProducto->setCheckState(Qt::Unchecked);
	lista->insertItem(0, nuevoProducto);
}
 
void ListaDeCompras::botonQuitarPresionado()
{
	if(!lista->currentItem()) {
		QMessageBox::warning(this, trUtf8("Lista de Compras"), trUtf8("Ningún producto ha sido seleccionado"));
		return;
	}
 
	int respuesta = QMessageBox::question(this, trUtf8("Lista de Compras"), trUtf8("¿Desea borrar el producto %1?").arg(lista->currentItem()->text()), QMessageBox::Yes|QMessageBox::No);
 
	if(respuesta == QMessageBox::Yes) {
		delete lista->currentItem();
	}
}
 
void ListaDeCompras::productoMarcado(QListWidgetItem* producto)
{
	if(producto->checkState() == Qt::Checked) {
		lista->takeItem(lista->currentRow());
		lista->insertItem(lista->count(), producto);
		lista->setCurrentRow(lista->count()-1);
		lista->currentItem()->setBackground(QColor("gray"));
	}
	else if(producto->checkState() == Qt::Unchecked) {
		lista->takeItem(lista->currentRow());
		lista->insertItem(0, producto);
		lista->setCurrentRow(0);
		lista->currentItem()->setBackground(QColor("white"));
	}
}

De las líneas 1 a 8 incluimos los archivos de cabecera necesarios para el ejemplo.

De las líneas 12 a 17 creamos los componentes que utilizaremos en el ejemplo: Layouts para organizar la interfaz gráfica y los widgets declarados en ListaDeCompras.cpp

De las líneas 19 a 26 configuramos la interfaz gráfica, agregamos los botones a un layout vertical y agregamos también un stretch a este layout con el fin de mantener los botones en la parte superior del widget y agregamos la lista y el layout de los botones al layout principal de nuestra aplicación.

De las líneas 28 a 30 conectamos las señales que emiten los widgets de la interfaz a los slots que proveen la funcionalidad.

De la línea 33 a la 52 implementamos el slot botonAgregarPresionado, que como lo indica en el nombre se ejecuta cuando se presiona el botón agregar.
En la línea 35 creamos una cadena que recibe el nombre del nuevo producto/tarea a través de un InputDialog.
De la línea 37 a la 40 verificamos que se haya capturado el nombre del nuevo elemento. De la línea 42 a 47 verificamos que no exista un elemento con el mismo nombre. Si no se cumpla alguna de las dos condiciones mostramos un mensaje de aviso para informar porque el elemento no fue agregado a la lista y salimos de esta función.
En la línea 49 creamos un nuevo elemento de la lista el cual será un objeto de la clase QListWidgetItem, esto lo hacemos mediante el constructor

QListWidgetItem ( const QString & text, QListWidget * parent = 0, int type = Type )

Este construcción recibe un parámetro obligatorio y dos opcionales, como parámetro obligatorio está el texto del elemento y como opcionales están el widget padre del elemento, que debe ser un QListWidget, y un entero que representa el tipo de elemento. Si especificamos el padre del QListWidgetItem este se agrega de forma automática a esta lista.

En la línea 50 establecemos el estado de la marca del elemento. Si no especificamos el estado de la marca, no se mostrará la checkbox que lo indica, debido a que queremos mostrar esta checkbox especificamos el estado aunque el elemento no este marcado en un principio.

En la línea 51 agregamos el elemento a nuestra lista mediante la función

void QListWidget::insertItem ( int row, QListWidgetItem * item )

Esta función recibe como parámetros el índice de la fila en el que queremos insertar el elemento y un apuntador al elemento que queremos agregar a la lista. Si ya hay un elemento en esta posición los demás elementos se recorren un lugar adelante en la lista para dejar un lugar al nuevo elemento.

De las líneas 54 a 66 implementamos el slot botonQuitarPresionado, el cual se ejecuta cuando se presiona el botón quitar.
De las líneas 56 a 59 verificamos que algún elemento de la línea este seleccionado, si no hay ningún elemento seleccionado entonces mostramos un mensaje que informe de esto al usuario y salimos de la función. En caso de que sí haya un elemento seleccionado mostramos un diálogo para pedir al usuario que confirme si desea borrar el elemento. Si presiona el botón que indica que desea borrar el elemento entonces borramos el elemento de la lista con la instrucción delete y esté será destruido, Qt detectará esto y automáticamente removerá el elemento de la lista.

De la línea 68 a 82 implementamos el slot productoMarcado, el cual se ejecuta cuándo marcamos o desmarcamos la checkbox de cada elemento.
En la línea 70 comprobamos si el estado del elemento que la lista nos indica que fue modificado cambió a marcado o desmarcado. Si el estado cambió a marcado entonces movemos el elemento al final de la lista, esto lo logramos con las líneas

71
72
lista->takeItem(lista->currentRow());
lista->insertItem(lista->count(), producto);

Debido a que no existe una función que nos permita mover un elemento de posición lo que hacemos es quitar el elemento e insertarlo en la nueva posición que deseamos.
En la línea 71 quitamos el elemento de la lista me diante la función takeItem, la cual recibe como parámetro el índice de la fila en la que se encuentra el item que queremos quitar. Luego en la línea 72 insertamos nuevamente el elemento mediante la función insertItem.

En la línea 73 actualizamos el elemento que está seleccionado en la lista para que apunte nuevamente al elemento que nos interesa y que dejó de estar seleccionado debido a que lo quitamos de la lista. En la línea 74 cambiamos el color del fondo del elemento mediante la función setBackground color, la cual recibe como parámetro un objeto QColor.

En la línea 76 comienza la serie de acciones que se ejecutarán si el estado del elemento cambia a desmarcado. Estas acciones son muy similares a las que realizamos si el elemento cambia su estado a marcado. El cambio de posición lo realizamos mediante las mismas dos funciones, takeItem, insertItem y setCurrentRow, lo único que cambia es la posición en la que lo insertaremos, antes era al final, ahora es al principio. Y finalmente cambiamos el color de fondo del elemento nuevamente a blanco.

Esto es todo en este artículo en la siguiente parte de este tutorial revisaremos los otros dos Item/View Widgets: QTableWidget y QTreeWidget.

Programación en Linux en el FLISOL-ESCOM

PésimoMaloRegularBuenoExcelente (4 votes, average: 4.00 out of 5)
Loading ... Loading ...

Este post es sólo para invitar a los visitantes y lectores del sitio a que asistan al Festival Latinoamericano Instalación SOftware Libre (FLISOL) de la sede Escuela Superior de Cómputo (ESCOM) el cuál se llevará a cabo el día sábado 24 de abril a partir de las 10:00 am. La dirección de la sede es:

Av. Juan de Dios Bátiz s/n esquina Miguel Othón de Mendizabal.
Unidad Profesional Adolfo López Mateos.
Col. Lindavista


Ver mapa más grande

El FLISOL es el evento más grande de difusión de Software Libre en Latinoamérica, el cuál se realiza anualmente desde el año 2005 y cuya principal actividad es, como su nombre lo indica, ayudar a los asistentes a instalar Software Libre en sus computadoras; Aunque no sólo se limita a esto, ya que también se imparten talleres y conferencias sobre el uso de aplicaciones de Software Libre y en algunos casos también sobre programación de aplicaciones.

En esta edición del FLISOL, tendremos la oportunidad de dar una plática de introducción al framework de desarrollo de aplicaciones Qt, sobre el cuál tenemos un tutorial en desarrollo aquí en el sitio. En dicha plática intentaremos dar respuesta a las preguntas que probablemente se haga alguien que no conocía Qt o un principiante en esta tecnología:

¿Qué es Qt? ¿Para qué sirve?
Definición de Framework, ventajas de utilizar uno.
Características principales de Qt.
Ejemplos de código “optimizado” gracias a la utilización de un framework.
¿Quién lo utiliza? ¿Dónde se utiliza?
Lista de industrias y compañías que utilizan Qt.
¿Porqué utilizar Qt?
Ventajas, desventajas y un vistazo a las características principales de Qt.
Ejemplos de código y aplicaciones.
¿Cómo puedo empezar con Qt?
Lista de sitios y material de referencia. Ejemplos introductorios.

También sería interesante organizar la visita entre varios de nosotros para evitar que alguien se pierda, para ir más seguros en grupo o para tener con quien conversar en los tiempos libres entre actividades.
Proponemos vernos en alguna estación del metro cercana a la mayoría de los que confirmen asistencia o en alguna conocida por todos y llegar juntos al evento, después que cada quien asista a la actividad que más le interese y reunirnos nuevamente para la comida, luego volver a separarnos de acuerdo a los intereses de cada uno y juntarnos al final para el regreso al metro. Eso o algo similar, se aceptan propuestas.

Así que la invitación ya está hecha, esperamos que asistan y si tienen alguna duda sobre la ubicación de la sede, horarios, lugares para ir a comer o cualquier otra cosa no duden en publicarla. Intentaremos responderla pronto.

Más información:
Sitio Oficial FLISOL
FLISOL México
FLISOL ESCOM

Tutorial de Qt4: Diálogos, comunicación con el usuario (Parte II)

PésimoMaloRegularBuenoExcelente (1 votes, average: 5.00 out of 5)
Loading ... Loading ...

En el artículo anterior revisamos la primera de las dos formas principales de utilizar diálogos en Qt, esto es creando clases que hereden de QDialog, implementando la funcionalidad de estas clases y gestionando las respuestas que recibimos a través de la función QDialog::exec()

En este artículo veremos la segunda forma de utilizar diálogos en una aplicación de Qt, esto es, utilizando las clases de diálogos estándar que nos proporciona Qt, estas clases son:

  • QMessageBox Permite mostrar mensajes de notificación al usuario.
  • QFileDialog Permite mostrar un diálogo que sirve para seleccionar un archivo o carpeta del sistema de archivos.
  • QInputDialog Permite mostrar un diálogo con un widget para que el usuario puede introducir información.
  • QColorDialog Muestra un diálogo para que el usuario pueda seleccionar un color.
  • QPrintDialog Muestra un diálogo para especificar configuraciones de la impresora.

A continuación mostraremos un ejemplo de uso de estos diálogos mediante una traducción/adaptación de el ejemplo Standar Dialogs de la documentación oficial de Qt, esta documentación la podemos encontrar en la dirección: http://qt.nokia.com/doc/4.6

El ejemplo se compone de los siguientes archivos:

  • Ventana.h
  • Ventana.cpp
  • main.cpp

Los archivos Ventana.h y Ventana.cpp componen la clase Ventana, la cual representa la ventana principal de la aplicación de ejemplo. Esta clase esta compuesta por dos columnas de widgets, una de ellas está compuesta por botones; Cada uno de ellos servirá para mostrar un diálogo estándar que nos permitirá obtener un dato del usuario. La segunda columna se compone de etiquetas y en cada una de ellas escribiremos la información que proporcionó el usuario a través del diálogo correspondientes. Dicha ventana se muestra en la siguiente imagen.

A continuación explicamos el código del archivo Ventana.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "ventana.h"
#include <QPushButton>
#include <QLabel>
#include <QGridLayout>
 
#include <QInputDialog>
#include <QColorDialog>
#include <QFileDialog>
#include <QFontDialog>
#include <QMessageBox>
#include <QErrorMessage>
 
Ventana::Ventana(){
	QGridLayout* layoutPrincipal = new QGridLayout;

De las líneas 1 a 11 incluimos los archivos de cabecera que necesitamos para este ejemplo.
En la línea 13 comienza el constructor de nuestra clase. En la línea 15 declaramos el layout con el que organizamos los componentes de nuestra ventana.

17
18
19
        botonObtenerTexto = new QPushButton(trUtf8("Obtener Texto"));
	botonObtenerEntero = new QPushButton(trUtf8("Obtener Entero"));
        (...)
32
33
34
35
	etiquetaObtenerTexto = new QLabel(trUtf8("\t\t\t\t"));
	etiquetaObtenerEntero = new QLabel(trUtf8("\t\t\t\t"));
	etiquetaObtenerDoble = new QLabel(trUtf8("\t\t\t\t"));
        (...)

De las líneas 17 a 45 creamos los widgets que utilizaremos en el ejemplo. No mostramos todas las líneas debido a que el código es muy repetitivo y las líneas son muy similares. En dónde escribimos (…) van líneas iguales a las anteriores pero para los demás widgets. El código del ejemplo se puede descargar mediante los links de la parte inferior de este artículo.

A partir de la línea 17 creamos los botones que servirán para mostrar cada uno de los diálogos estándar de Qt. A partir de la línea 32 y hasta la 45 creamos las etiquetas en las que escribiremos el valor de retorno de cada uno de los diálogos.

47
48
49
50
	etiquetaObtenerTexto->setFrameStyle(QFrame::Box);
	etiquetaObtenerEntero->setFrameStyle(QFrame::Box);
	etiquetaObtenerDoble->setFrameStyle(QFrame::Box);
        (...)
62
63
64
65
	layoutPrincipal->addWidget(botonObtenerTexto, 0, 0);
	layoutPrincipal->addWidget(etiquetaObtenerTexto, 0, 1);
	layoutPrincipal->addWidget(botonObtenerEntero, 1, 0);
        (...)
93
94
95
96
        connect(botonObtenerTexto, SIGNAL(clicked()), this, SLOT(obtenerTexto()));
	connect(botonObtenerEntero, SIGNAL(clicked()), this, SLOT(obtenerEntero()));
	connect(botonObtenerDoble, SIGNAL(clicked()), this, SLOT(obtenerDoble()));
        (...)

De las líneas 47 a 60 establecemos un marco para las etiquetas que mostrarán la respuesta de los diálogos. En las líneas 62 a 89 configuramos la apariencia de la interfaz de usuario utilizando un QGridLayout. Y finalmente, de las líneas 93 a 106 conectamos cada botón con su slot correspondiente, cada slot mostrará un diálogo distinto para cada botón y procesará la respuesta del usuario.

A partir de la línea 109 comienza la implementación de los slots, en todos ellos realizamos las siguiente acciones:

  1. Creamos una variable para almacenar la información que ingresa el usuario por medio del diálogo.
  2. Ejecutamos el diálogo para obtener la información del usuario y el valor de respuesta, este último está determinado por el botón que presiona el usuario.
  3. Evaluamos el valor de respuesta del diálogo.
  4. Dependiendo del valor de la respuesta decidimos de que manera procesar la información capturada, si es que la hay.

A continuación revisamos los slots que conectamos con cada uno de los botones, comenzaremos con los slots que hacen uso de los diálogos que nos ofrece la clase QInputDialog.

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
void Ventana::obtenerTexto()
{
	QString texto = QInputDialog::getText(this, trUtf8(""), trUtf8(""), QLineEdit::Normal, trUtf8(""), &ok);
 
	if(ok)
		etiquetaObtenerTexto->setText(texto);
}
 
void Ventana::obtenerEntero()
{
	int entero = QInputDialog::getInt(this, trUtf8(""), trUtf8(""), 42, 41, 43, 1, &ok);
	if(ok)
		etiquetaObtenerEntero->setText(QString::number(entero));
}
 
void Ventana::obtenerDoble()
{
	double doble = QInputDialog::getDouble(this, trUtf8(""), trUtf8(""), 9.9, 5, 15, 2, &ok);
	if(ok)
		etiquetaObtenerDoble->setText(QString::number(doble));
}
 
void Ventana::obtenerElemento()
{
	QStringList listaElementos;
	listaElementos << "Elemento 1" << "Elemento 2" << "Elemento 3";
	QString elemento = QInputDialog::getItem(this, trUtf8(""), trUtf8(""), listaElementos, 0,  false, &ok);
	if(ok)
		etiquetaObtenerElemento->setText(elemento);
}

De la línea 109 a la 115 implementamos el slot obtenerTexto, en él mostramos un diálogo que nos permitirá obtener un valor de texto capturado por el usuario. Este diálogo lo ejecutamos mediante la función

QString QInputDialog::getText ( QWidget * parent, const QString & title, const QString & label, QLineEdit::EchoMode mode = QLineEdit::Normal, const QString & text = QString(), bool * ok = 0, Qt::WindowFlags flags = 0 )

Está función recibe como parámetros:

  • Un apuntador al widget que deseamos establecer como su padre.
  • El texto que se mostrará en la barra de título del diálogo.
  • El texto que mostrará el diálogo.
  • El modo (EchoMode) en el que se mostrará el texto ingresado. Aqui podemos establecer un valor de la enumeración EchoMode el cual indicará si el texto debe ser visible, que no se muestre o que se muestren caracteres para enmascarar contraseñas (como asteriscos)
  • El valor predeterminado que se mostrará en el campo de texto
  • Un apuntador a una variable que almacena el valor que indica que botón fue presionado.
  • Las flags (banderas u opciones) del diálogo, las cuales establecen propiedades del sistema de ventanas para un widget, como los botones que se muestran en la barra de título o si debe mostrar barra de título o no. Los valores posibles son parte de la enumeración Qt::WindowFlags

Si el usuario no cierra el diálogo y en cambio presiona algún botón, entonces escribimos el valor de la respuesta en la etiqueta correspondiente.

De la línea 117 a 122 implementamos el slot obtenerEntero, en él mostramos un diálogo que contiene una spinBox que permitirá al usuario establecer un valor numérico entero. Este diálogo lo ejecutamos mediante la función

int QInputDialog::getInt ( QWidget * parent, const QString & title, const QString & label, int value = 0, int min = -2147483647, int max = 2147483647, int step = 1, bool * ok = 0, Qt::WindowFlags flags = 0 )

Los primeros tres y los dos últimos parámetros de está “familia” de funciones y de algunos de los otros diálogos estándar son iguales, indican el widget padre, el título del diálogo, el texto que se mostrará en el diálogo, un apuntador a la variable donde se almacenará la respuesta al diálogo y una lista de flags u opciones del diálogo.

A partir del cuarto parámetro y en orden, los parámetros específicos de este diálogo son:

  • El valor predeterminado que al que se establecerá la spinbox cuando se muestre el diálogo
  • El valor mínimo al que se puede establecer el valor de la spinbox
  • El valor máximo al que se puede establecer el valor de la spinbox
  • La cantidad en que se incrementará o decrementará el valor de la spinbox al presionar las flechas del extremo (step o paso)

De las líneas 124 a 129 implementamos el slot obtenerDoble, en él mostramos un diálogo muy similar al que del slot obtenerEntero con la diferencia de que el valor de la spinbox podrá ser un valor decimal o de punto flotante de doble precisión. Este diálogo lo ejecutamos mediante la función

double QInputDialog::getDouble ( QWidget * parent, const QString & title, const QString & label, double value = 0, double min = -2147483647, double max = 2147483647, int decimals = 1, bool * ok = 0, Qt::WindowFlags flags = 0 )

Los parámetros de esta función son muy similares a la función getInt salvo por el séptimo parámetro, el cuál indica el número de decimales del número, el valor por defecto es de uno.

De la línea 131 a 138 implementamos el slot obtenerElemento, en él mostramos un diálogo que contiene una comobox que permite al usuario elegir un valor de una lista que indiquemos. Este diálogo lo ejecutamos mediante la función

QString QInputDialog::getItem ( QWidget * parent, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true, bool * ok = 0, Qt::WindowFlags flags = 0 )

Esta función recibe del cuarto al sexto parámetro:

  • Una lista de cadenas de texto que serán los elementos de la combobox
  • La posición del elemento seleccionado por defecto, si no se especifica será cero
  • Un valor booleano que indica si la combobox será editable
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
void Ventana::obtenerColor()
{
	QColor color = QColorDialog::getColor();
	if(color.isValid()) {
		etiquetaObtenerColor->setText(color.name());
		etiquetaObtenerColor->setPalette(QPalette(color));
		etiquetaObtenerColor->setAutoFillBackground(true);
	}
}
 
void Ventana::obtenerFuente()
{
	QFont fuente = QFontDialog::getFont(&ok);
	if(ok)
		etiquetaObtenerFuente->setText(fuente.toString());
}

De las líneas 140 a 148 implementamos el slot obtenerColor, en el mostramos un diálogo que contiene controles especializados para permitir que el usuario eliga un color. Este diálogo lo mostramos mediante la función

QColorDialog::getColor( const QColor & initial, QWidget * parent, const QString & title, ColorDialogOptions options = 0 )

Esta función recibe como parámetros:

  • Un objeto de la clase QColor que indica el color inicial que se establecerá en el diálogo, si no se especifica ninguno el color blanco será el seleccionado
  • El widget padre del diálogo
  • El título del diálogo
  • Miembros de la enumeración ColorDialogOptions, que permiten establecer algunas propiedades del diálogo como mostrar canal alfa o usar el diálogo nativo del sistema operativo

De la línea 150 a 155 implementamos el slot obtenerFuente, el cual muestra un diálogo que incluye controles especiales para que el usuario pueda seleccionar una fuente para el texto. Dicho diálogo se muestra mediante la función

QFont QFontDialog::getFont(bool *ok, QWidget *parent)

Dicha función tiene múltiples sobrecargas en las cuales se pueden establecer valores iniciales y configuraciones del diálogo similares a las de los diálogos anteriores pero en este ejemplo utilizamos una función que sólo recibe como parámetros el apuntador a la variable que almacena la respuesta que da el usuario al diálogo y un apuntador al widget padre de este diálogo.

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
void Ventana::obtenerDirectorioExistente()
{
	QString directorio = QFileDialog::getExistingDirectory(this, trUtf8(""), etiquetaObtenerDirectorioExistente->text(), QFileDialog::ShowDirsOnly);
	if(!directorio.isEmpty())
		etiquetaObtenerDirectorioExistente->setText(directorio);
}
 
void Ventana::obtenerArchivoAbrir()
{
	QString filtroSeleccionado;
	QString Nombre = QFileDialog::getOpenFileName(this,
								trUtf8(""),
								etiquetaObtenerArchivoAbrir->text(),
								trUtf8("Todos los archivos (*);;Archivos de Cabecera C/C++ (*.h);;Archivos de Código Fuente C++ (*.cpp)"),
								&filtroSeleccionado, 0);
	if (!Nombre.isEmpty())
		etiquetaObtenerArchivoAbrir->setText(Nombre);
}
 
void Ventana::obtenerArchivosAbrir()
{
	QStringList archivos = QFileDialog::getOpenFileNames(
								this,
								trUtf8(""),
								"",
								trUtf8("Todos los Archivos (*);;Archivos de Cabecera C/C++ (*.txt);;Archivos de Código Fuente C++ (*.cpp)"));
 
	if (archivos.count()) {
		etiquetaObtenerArchivosAbrir->setText(QString("[%1]").arg(archivos.join(", ")));
	}
}
 
void Ventana::obtenerArchivoGuardar()
{
	QString nombreArchivo = QFileDialog::getSaveFileName
								(this,
								trUtf8(""),
								etiquetaObtenerArchivoGuardar->text(),
								trUtf8("Todos los Archivos (*);;Archivos de Cabecera C/C++ (*.txt);;Archivos de Código Fuente C++ (*.cpp)"));
 
	if (!nombreArchivo.isEmpty())
		etiquetaObtenerArchivoGuardar->setText(nombreArchivo);
}

De las líneas 157 a 207 implementamos los slots que hacen uso de las funciones estáticas de la clase QFileDialog.

De la línea 157 a 162 implementamos el slot obtenerDirectorioExistente en el cual ejecutamos un diálogo que mostrará una ventana de exploración del sistema de archivos y que nos permitirá seleccionar una carpeta o directorio. Este diálogo lo mostramos con la función

QString getExistingDirectory ( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), Options options = ShowDirsOnly )

Esta función recibe como parámetros

  • Un apuntador al widget padre del diálogo
  • El título del diálogo
  • La ruta del directorio en dónde se desea comenzar a buscar
  • Miembros de la enumeración QFileDialog::Options que permiten configurar opciones del diálogo como el sólo mostrar directorios o utilizar un diálogo no nativo

De la línea 176 a 187 implementamos el slot obtenerArchivoAbrir el cual funciona de manera muy similar al slot anterior con la diferencia de que este permite seleccionar un archivo en lugar de un directorio. Mostramos el diálogo utilizado en este slot con la función

QString QFileDialog::getOpenFileName ( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedFilter = 0, Options options = 0 )

En esta función el último y los tres primeros parámetros son iguales al de la función del slot anterior. Los parámetros propios de esta función son:

  • Como cuarto parámetro, una cadena que representa los filtros que podrán ser aplicados al diálogo, este filtro determina que tipo de archivo se muestra. Para cada tipo de archivo se escribe una descripción y entre paréntesis la extensión del tipo de archivo. Separamos cada tipo de archivo mediante dos caracteres punto y coma (;;).
  • Como quinto parámetro, una cadena que indique el filtro seleccionado actualmente.

De la línea 176 a la 187 implementamos el slot obtenerArchivosAbrir el cual muestra un diálogo casi igual al del slot anterior con la diferencia de que este permite al usuario seleccionar más de un archivo. Mostramos el diálogo utilizado en este slot con la función

QStringList	QFileDialog::getOpenFileNames ( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedFilter = 0, Options options = 0 )

Los parámetros de la función utilizada para ejecutar el diálogo son iguales a los de la función utilizada para abrir un solo archivo.

De la línea 189 a 199 implementamos el slot obtenerArchivoGuardar el cual muestra un diálogo que permite guardar un archivo al usuario y eligiendo su ubicación y especificando su nombre. El diálogo utilizado en este slot lo ejecutamos mediante la función

QString QFileDialog::getSaveFileName ( QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedFilter = 0, Options options = 0 )

Los parámetros de esta función son iguales que los de la función utilizada para ejecutar el diálogo que permite abrir archivos. Si especificamos un nombre que coincida con el de un archivo existente se mostrará otro diálogo solicitando la confirmación del usuario, este diálogo muestra dos botones de respuesta: Aceptar y Cancelar.

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
void Ventana::mostrarMensajeCritico()
{
	QMessageBox::StandardButton respuesta = QMessageBox::critical(
			this,
			trUtf8(""),
			trUtf8(""),
			QMessageBox::Abort | QMessageBox::Retry | QMessageBox::Ignore);
 
	if (respuesta == QMessageBox::Abort)
		etiquetaMostrarMensajeCritico->setText(tr("Abortar"));
	else if (respuesta == QMessageBox::Retry)
		etiquetaMostrarMensajeCritico->setText(tr("Reintentar"));
	else
		etiquetaMostrarMensajeCritico->setText(tr("Ignorar"));
}
 
void Ventana::mostrarMensajeInformacion()
{
	QMessageBox::StandardButton respuesta;
	respuesta = QMessageBox::information(this, trUtf8(""), trUtf8("Este es un mensaje de información"));
	if (respuesta == QMessageBox::Ok)
		etiquetaMostrarMensajeInformacion->setText(tr("OK"));
	else
		etiquetaMostrarMensajeInformacion->setText(tr("Escape"));
}
 
void Ventana::mostrarMensajePregunta()
{
	QMessageBox::StandardButton respuesta;
	respuesta = QMessageBox::question(this, trUtf8(""),
									trUtf8("Este es un mensaje con una pregunta"),
									QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
	if (respuesta == QMessageBox::Yes)
		etiquetaMostrarMensajePregunta->setText(tr("Sí"));
	else if (respuesta == QMessageBox::No)
		etiquetaMostrarMensajePregunta->setText(tr("No"));
	else
		etiquetaMostrarMensajePregunta->setText(tr("Cancelar"));
}
 
void Ventana::mostrarMensajeAdvertencia()
{
	QMessageBox msgBox(QMessageBox::Warning, trUtf8("QMessageBox::warning()"),
					   trUtf8("Este es un mensaje de advertencia"), 0, this);
	msgBox.addButton(trUtf8("Guardar Otra Vez"), QMessageBox::AcceptRole);
	msgBox.addButton(trUtf8("Continuar"), QMessageBox::RejectRole);
	if (msgBox.exec() == QMessageBox::AcceptRole)
		etiquetaMostrarMensajeAdvertencia->setText(tr("Guardar Otra Vez"));
	else
		etiquetaMostrarMensajeAdvertencia->setText(tr("Continuar"));
}

A partir de la línea 201 y hasta el fin del archivo en la línea 251 implementamos los slots que muestran los diálogos de la case QMessageBox. Entre las líneas 201 y 215 implementamos el slot mostrarMensajeCritico el cual permite mostrar un diálogo con un icono de error que normalmente sirve para indicar que ocurrió algún error grave en la aplicación. Mostramos este diálogo mediante la función

StandardButton QMessageBox::critical ( QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton )

Dicha función nos devuelve un valor de la enumeración StandarButttons, la cual contiene todos los posibles valores que devuelve un diálogo al presionar cada uno de los botones disponibles, como: Aceptar, Cancelar, Reintentar, Sí, Sí a todo, No, Cancelar.

Las cuatro funciones de la clase QMessageBox que revisaremos y que nos sirven para mostrar un diálogo de información reciben los mismos parámetros, los cuales son:

  • Un apuntador al widget padre del diálogo
  • El título del diálogo
  • El texto que deseamos mostrar en el diálogo
  • Una lista de valores de la enumeración StandarButton separadados por caracteres 2de barra”, (el que se usa para un OR a nivel bit en C/C++) en donde cada valor indica que se debe mostrar su botón correspondiente
  • Un valor de la enumeración StandarButtons el cual indica que botón se establecerá como predeterminado, es decir sobre cual se hará un efectro de clic al presionar la tecla enter al estar el diálgo activo

Entre las líneas 217 y 225 implementamos el slot mostrarMensajeInformacion en el cual mostramos un diálogo que sirve para mostrar información al usuario, como un aviso sobre la conclusión de una tarea o una notificación de algún evento. Mostramos el diálogo utilizado mediante la función

StandardButton QMessageBox::information ( QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton )

De la línea 227 a 239 implementamos el slot mostrarMensajePregunta en el cual mostramos un diálogo con icono de un signo de interrogación, este diálogo sirve para realizar una pregunta al usuario o solicitar su confirmación u aprobación para un proceso, como al guardar o borrar un archivo. Mostramos este diálogo mediante la función

StandardButton QMessageBox::question ( QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton )

Y finalmente de le la línea 241 a la 251 implementamos el slot mostrarMensajeAdvertencia en el cual mostramos un diálogo con que sirve para mostrar un mensaje de advertencia, como información sobre un error poco grave. Este diálogo lo mostramos mediante la función

StandardButton QMessageBox::warning ( QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton )

Con esa función concluimos la revisión del código del archivo Ventana.cpp. En el archivo main.cpp simplemente creamos un objeto de esta clase y lo mostramos en pantalla.

Eso es todo en este artículo. En la siguiente parte de este tutorial veremos como utilizar los widgets QListWidget, QTableWidget y QTreeWidget, los cuales nos permiten visualizar un conjunto de datos a manera de lista, tabla o árbol de manera sencilla. Estos widgets son parte del framework modelo/vista que Qt provee.

Tutorial de Qt4: Diálogos, comunicación con el usuario (Parte I)

PésimoMaloRegularBuenoExcelente (No Ratings Yet)
Loading ... Loading ...

En el artículo anterior de este tutorial revisamos a detalle el widget QMainWindow el cuál nos sirve para crear la ventana principal de nuestra aplicación. En este artículo hablaremos acerca de los diálogos, pequeñas ventanas secundarias que sirven para comunicarse con el usuario.

Los diálogos son útiles en ocasiones en las que requerimos la confirmación del usuario antes de ejecutar una acción, como al guardar o eliminar un archivo o al salir de una aplicación, también suelen utilizarse para obtener pequeñas cantidades de información, como la palabra a buscar en un diálogo de buscar y reemplazar o el nombre que se desea dar a un marcador/favorito en un navegador web.

Podemos utilizar diálogos de Qt de dos formas distintas, una es creándolos nosotros como lo hemos hecho en otros artículos de este tutorial y la otra es utilizar el API estática de diálogos comúnmente utilizados que nos provee Qt, entre estos diálogos se encuentran los de petición de información al usuario o los de selección de carpetas, archivos, fuentes o colores.

Al especificar el widget padre para un QDialog, la posición por defecto será en el centro y encima del widget padre. También compartirá la entrada del padre en la barra de tareas del sistema operativo.

Podemos mostrar un diálogo en pantalla con una de las siguientes dos funciones:

void QWidget::show();

Esta función se hereda de QWidget y es equivalente a llamar a la función setVisible con un parámetro booleano con valor de  true, mostrar un diálogo a través de esta función es útil si queremos que el usuario pueda continuar interactuando con la ventana que mostró el diálogo, los diálogos que permiten dicha interacción se conocen con el nombre de diálogos no modales.

int QDialog::exec();

Esta función sirve para mostrar un diálogo modal, este es un tipo de diálogos que bloquean el acceso a las demás ventanas de la aplicación. Mostrar un diálogo con la función exec() permite obtener el valor de la respuesta elegida por el usuario. A continuación mostramos un ejemplo para observar de mejor manera la diferencia entre show y exec. El ejemplo se compone de los siguientes archivos:

  • DialogoModal.h
  • DialogoModal.cpp
  • Ventana.h
  • Ventana.cpp
  • main.cpp

La clase DialogoModal, representa un diálogo personalizado muy simple que sólo muestra una etiqueta en el lugar en dónde se colocarían los widgets en un diálogo de una aplicación real, está clase nos servirá para ver cómo podemos gestionar las respuestas que puede emitir un diálogo modal.

El código del archivo DialogoModal.cpp es el siguiente:

NOTA: Sólo explicaremos las líneas relevantes para el ejemplo o que no hayan sido explicadas en artículos anteriores de este tutorial.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "dialogomodal.h"
 
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
 
DialogoModal::DialogoModal()
{
	QVBoxLayout* layoutPrincipal = new QVBoxLayout;
	QHBoxLayout* layoutBotones = new QHBoxLayout;
 
	nombre = new QLabel(trUtf8("Diálogo Modal"));
	botonAceptar = new QPushButton(trUtf8("Aceptar"));
	botonRechazar = new QPushButton(trUtf8("Rechazar"));
	botonOtro = new QPushButton(trUtf8("Otro"));
 
	nombre->setFont(QFont("Sans-Serif", 15));
 
	layoutBotones->addStretch();
	layoutBotones->addWidget(botonAceptar);
	layoutBotones->addWidget(botonRechazar);
	layoutBotones->addWidget(botonOtro);
 
	layoutPrincipal->addWidget(nombre);
	layoutPrincipal->addLayout(layoutBotones);
 
	setLayout(layoutPrincipal);
 
	connect(botonAceptar, SIGNAL(clicked()), this, SLOT(accept()));
	connect(botonRechazar, SIGNAL(clicked()), this, SLOT(reject()));
	connect(botonOtro, SIGNAL(clicked()), this, SLOT(botonOtroPresionado()));
}
 
void DialogoModal::botonOtroPresionado() {
	done(99);
}

De la línea 14 a la 16 creamos los widgets que componen nuestro diálogo. Los botones botonAceptar, botonRechazar y botonOtro representan las distintas opciones con las que el usuario puede responder al mensaje (o lo que le mostremos) en el diálogo.

De las líneas 30 a 32 conectamos la señal clicked() de los botones al slot correspondiente con la acción que queremos que realicen. Los botones botonAceptar y botonRechazar se conectan a los slots accept() y reject(), los cuáles están previamente definidos en QDialog y se encargan de ocultar el diálogo y devolver el código respuesta correspondiente, 1 para accept (aceptar) y 0 para reject (rechazar), como valor de retorno de la función exec.

Por otra parte el botón de nombre botonOtro se conecta a un slot botonOtroPresionado el cuál es implementado por nosotros. Dicha implementación comienza en la línea 35 y en realidad es sólo una “envoltura” para llamar al slot:

QDialog::done(int r)

El cuál también es parte de QDialog, este slot nos permite hacer algo similar a accept() y reject(), es decir, ocultar el diálogo y enviar un código de respuesta, con la diferencia de que en done() podemos especificar el código de respuesta que queremos enviar. En este caso enviamos el número 99, pero puede ser cualquier otro entero. El código del archivo Ventana.cpp es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include "ventana.h"
 
#include <QHBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QApplication>
#include <QMessageBox>
 
Ventana::Ventana()
{
	QGridLayout* layoutPrincipal = new QGridLayout;
 
	botonDialogoModal = new QPushButton(QObject::trUtf8("Mostrar Diálogo Modal"));
	botonDialogoNoModal = new QPushButton(QObject::trUtf8("Mostrar Diálogo No Modal"));
 
	resultadoDialogoModal = new QLabel("\t\t");
 
	dialogoModal = new DialogoModal;
	dialogoNoModal = new QDialog(this);
 
	resultadoDialogoModal->setFrameStyle(1);
 
	layoutPrincipal->addWidget(botonDialogoModal, 0, 0);
	layoutPrincipal->addWidget(resultadoDialogoModal, 0, 1);
	layoutPrincipal->addWidget(botonDialogoNoModal, 1, 0);
 
	setLayout(layoutPrincipal);
	setWindowFlags(Qt::Window);
	setWindowTitle(trUtf8("Diálogos Personalizados - http://programacion-linux.com/"));
 
	connect(botonDialogoModal, SIGNAL(clicked()), this, SLOT(ejecutar()));
	connect(botonDialogoNoModal, SIGNAL(clicked()), dialogoNoModal, SLOT(show()));
	connect(this, SIGNAL(rejected()), this, SLOT(salir()));
}
 
void Ventana::salir() {
	QApplication::exit(0);
}
 
void Ventana::ejecutar() {
	int respuesta = dialogoModal->exec();
 
	QMessageBox::information(this, "", QString::number(respuesta));
 
	switch(respuesta) {
	case 0:
		resultadoDialogoModal->setText(trUtf8("Rechazar presionado"));
		break;
 
	case 1:
		resultadoDialogoModal->setText(trUtf8("Aceptar presionado"));
		break;
 
	default:
		resultadoDialogoModal->setText(trUtf8("Otro presionado"));
		break;
	}
}

De las líneas 15 a 21 creamos los widgets que componen nuestra ventana. En la línea 18 creamos una etiqueta que mostrará la respuesta de nuestro diálogo modal y le indicamos que muestre dos tabuladores como texto para que tenga un tamaño mínimo que pueda contener la respuesta del diálogo, esto es sólo por motivos estéticos.

En la línea 21 creamos un diálogo que utilizaremos como diálogo no modal e indicamos que nuestra clase ventana será su padre, esto provocará que el diálogo no modal se muestre centrado respecto a la posición de nuestra ventana; Este comportamiento no lo observamos para nuestro diálogo modal porque no hemos establecido un padre para él.

En la línea 23 establecemos un estilo de línea para el borde/marco de la etiqueta que mostrará la respuesta del diálogo modal. De las líneas 33 a 35 realizamos las conexiones de señales y slots. En la línea 35 conectamos la señal, rejected() de nuestra ventana al slot salir, el cual es implementado por nostros y que sólo es una “envoltura” para la función QApplication::exit() que hará que termine nuestra aplicación. La señal rejected() también se emite cuándo se usa el boton cerrar de la barra de título de un diálogo. En las líneas 33 y 34 conectamos la señal clicked de los botones a los slots que mostrarán el diálogo correspondiente, modal o no modal, el diálogo no modal lo mostramos llamando directamente a show debido a que esta función no devuelve ningún código de respuesta que tengamos que gestionar.

El diálogo modal lo mostramos en el slot ejecutar(), implementado por nosotros en la línea 42  y asignamos su resultado a una variable, después procesamos el valor de este resultado, en este caso comparamos dicho valor con los códigos de resultado usuales y el que definimos nosotros, dependiendo de con que valor coincida modificamos el valor de la eitqueta resultadoDialogoModal.

Es todo en la primera parte de este artículo, en la siguiente parte continuaremos con el tema de los diálogos; Mostraremos la otra forma de obtener información de parte del usuario: Utilizando los diálogos estándar de Qt.

Tutorial de Qt 4: QMainWindow, la ventana principal de la aplicación

PésimoMaloRegularBuenoExcelente (No Ratings Yet)
Loading ... Loading ...

En el artículo anterior de este tutorial vimos como implementar la funcionalidad de una aplicación gráfica de Qt utilizando señales y slots. En este artículo revisaremos a detalle un widget especial, QMainWindow, el cuál posee características especiales para ser utilizado como la ventana principal de las aplicaciones Qt. La estructura de la QMainWindow se puede ver en la siguiente imagen DiagramaQMainWindow

Una QMainWindow puede estar compuesta de las siguientes cinco áreas o secciones:

  • Menu Bar como su nombre lo indica esta barra contiene menús, los cuales están compuestos por elementos de texto o etiquetas que indican las acciones que puede realizar la aplicación y que se ejecutan al hacer clic sobre ellas. Normalmente sólo existe una de ellas en la ventana y está colocada en la parte superior, debajo de la barra de título. Algunos ejemplos muy conocidos de menús que suelen colocarse en esta barra son Archivo, Edición, Herramientas o Ayuda.

menuArchivo

  • Toolbars al igual que la barra de menús, esta clase de barras, conocida como barra de herramientas está compuesta por las acciones que puede realizar la aplicación, con la diferencia de que en esta barra dichas acciones se muestran mediante iconos en lugar de etiquetas. Estas barras suelen estar ubicadas debajo de la barra de menús y podemos encontrar una o más de estas barras en una ventana. Un ejemplo muy conocido de iconos colocados en este tipo de barras son los de Guardar, representado por un diskette o Imprimir, representado por una impresora.

barraDeHerramientas

  • Status Bar Esta barra, conocida como barra estatus o de estado, normalmente está colocada en la parte inferior de la ventana, en ella se muestran mensajes informativos sobre el estado de la aplicación, las acciones que está realizando o la descripción del elemento al que estemos apuntando con el mouse.
  • Dock Widgets Este es un tipo de widgets que pueden ser acoplados o ajustados alrededor del widget central de una aplicación o permitir que “floten” libremente en el escritorio, al igual que las barras de herramientas contienen iconos y botones que permiten ejecutar acciones que proporciona la aplicación.

DockWidgetTabla

  • Central Widget Este widget representa el área de trabajo de una aplicación, como la tabla de celdas de una aplicación en hoja de cálculo o el área de texto de un procesador de textos.

Podemos reconocer estás secciones en un buen número de aplicaciones, como ejemplo presentamos la ventana de Open Office Writer (clic para ampliar).

VentanaPrincipalOO

A continuación mostraremos un sencillo ejemplo de una aplicación que basada en una QMainWindow, la cual contendrá una etiqueta como widget central la cual cambiará el texto que muestra dependiendo de la acción que ejecutemos, estas acciones se encontrarán en una barra de menús y una barra de herramientas también incluiremos una barra de estatus.

La aplicación está compuesta por los siguientes tres archivos:

  • ventanaprincipal.h es el archivo de encabezado de la clase VentanaPrincipal, contiene la declaracion de las variables  y la definición de las funciones que utilizaremos en esta aplicación.
  • ventanaprincipal.cpp es el archivo fuente de la clase VentanaPrincipal, contiene la implementación de las funciones declaradas en el archivo de encabezado.
  • main.cpp

A continuación revisaremos a detalle los archivos de la aplicación, sólo explicaremos las secciones que no hayan sido revisadas en partes anteriores de este tutorial o que sean relevantes en este contexto

ventanaprincipal.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef VENTANAPRINCIPAL_H
#define VENTANAPRINCIPAL_H
 
#include <QMainWindow>
 
class QLabel;
class QToolBar;
class QAction;
class QMenu;
 
class VentanaPrincipal : public QMainWindow
{
Q_OBJECT
 
public:
    VentanaPrincipal();
 
private slots:
    void accionNuevoLanzada();
    void accionAbrirLanzada();
    void accionAcercaDeLanzada();
    void accionSalirLanzada();
 
private:
    QMenu* menuArchivo;
    QMenu* menuAyuda;
    QToolBar* barraDeHerramientas;
    QAction* accionNuevo;
    QAction* accionAbrir;
    QAction* accionAcercaDe;
    QAction* accionSalir;
    QLabel* widgetCentral;
};
#endif

En la línea 4 incluimos el archivo de cabecera QMainWindow el cual contiene la definición de la clase en la que basaremos nuestra ventana principal.

En la línea 11 definimos nuestra clase VentanaPrincipal e indicamos que heredará de QMainWindow.

De la líneas 18 a 22 declaramos los slots por medio de los cuales implementaremos la funcionalidad de nuestra aplicación.

Y finalmente de las líneas 24 a 32 declaramos las variables que utilizaremos en la aplicación.

ventanaprincipal.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include "ventanaprincipal.h"
 
#include <QMenuBar>
#include <QToolBar>
#include <QLabel>
#include <QStatusBar>
#include <QMessageBox>
 
VentanaPrincipal::VentanaPrincipal()
{
    menuArchivo = menuBar()->addMenu(trUtf8("&Archivo"));
    menuAyuda = menuBar()->addMenu(trUtf8("A&yuda"));
 
    barraDeHerramientas = addToolBar(trUtf8("&Archivo"));
 
    widgetCentral = new QLabel(trUtf8("Widget central"));
    widgetCentral->setFont(QFont("Sans-Serif", 25));
 
    accionNuevo = new QAction(QIcon("iconos/nuevo.png"), trUtf8("&Nuevo"), this);
    accionNuevo->setShortcut(QKeySequence::New);
    accionNuevo->setStatusTip(trUtf8("Crear un nuevo archivo"));
 
    accionAbrir = new QAction(QIcon("iconos/abrir.png"), trUtf8("&Abrir"), this);
    accionAbrir->setShortcut(QKeySequence::Open);
    accionAbrir->setStatusTip(trUtf8("Abrir un archivo existente"));
 
    accionSalir = new QAction(QIcon("iconos/salir.png"), trUtf8("&Salir"), this);
    accionSalir->setShortcut(QKeySequence::Quit);
    accionSalir->setStatusTip(trUtf8("Salir de la aplicación"));
 
    accionAcercaDe = new QAction(QIcon("iconos/salir.png"), trUtf8("&Acerca de"), this);
    accionAcercaDe->setShortcut(QKeySequence("Ctrl+d"));
    accionAcercaDe->setStatusTip(trUtf8("Información sobre esta aplicación"));
 
    menuArchivo->addAction(accionNuevo);
    menuArchivo->addAction(accionAbrir);
    menuArchivo->addSeparator();
    menuArchivo->addAction(accionSalir);
 
    menuAyuda->addAction(accionAcercaDe);
 
    barraDeHerramientas->addAction(accionNuevo);
    barraDeHerramientas->addAction(accionAbrir);
    barraDeHerramientas->addSeparator();
    barraDeHerramientas->addAction(accionSalir);
 
    setCentralWidget(widgetCentral);
    statusBar()->showMessage(trUtf8("Bienvenido"));
    setWindowTitle("Ventana Principal");
    setMinimumSize(200, 200);
 
    connect(accionNuevo, SIGNAL(triggered()),
            this, SLOT(accionNuevoLanzada()));
 
    connect(accionAbrir, SIGNAL(triggered()),
            this, SLOT(accionAbrirLanzada()));
 
    connect(accionAcercaDe, SIGNAL(triggered()),
            this, SLOT(accionAcercaDeLanzada()));
 
    connect(accionSalir, SIGNAL(triggered()),
            this, SLOT(accionSalirLanzada()));
}
 
void VentanaPrincipal::accionNuevoLanzada()
{
    widgetCentral->setText(trUtf8("Acción \"Nuevo\" lanzada"));
    this->resize(QSize(widgetCentral->sizeHint().width(), 200));
}
 
void VentanaPrincipal::accionAbrirLanzada()
{
    widgetCentral->setText(trUtf8("Acción \"Abrir\" lanzada"));
    this->resize(QSize(widgetCentral->sizeHint().width(), 200));
}
 
void VentanaPrincipal::accionAcercaDeLanzada()
{
    QMessageBox::about(this, this->windowTitle(), trUtf8("Aquí se debe colocar información sobre la aplicación y la compañia que la desarolla\n\nTutoriales, artículos y enlaces de programación en:\nhttp://www.programacion-linux.com"));
}
 
void VentanaPrincipal::accionSalirLanzada()
{
    exit(0);
}

De las líneas 1 a 7 incluimos los archivos de cabecera necesarios para implementar la aplicación.

En las línea 11 inicializamos la variable menuArchivo la cual representa un menú que podemos incluir en la barra de menús de la QMainWindow, para lograrlo utilizamos las funciones

QMenuBar* QMainWindow::menuBar()

Devuelve una referencia a una barra de menús que es creada al llamar a la función por primera vez.

QMenu* QMenuBar::addMenu(QString &texto)

Devuelve una referencia a un menú que se creará al llamar a la función y que mostrará en pantalla el texto indicado en la cadena de caracteres que se pasa como parámetro. En la línea 12 realizamos lo mismo para el menú Ayuda.

En la línea 14 inicializamos la variable que representa a una barra de herramientas. La función utilizada es:

QToolBar* QMainWindow::addToolBar(QString &texto);

y trabaja de manera muy similar a las descritas anteriormente, es decir, devuelve una referencia a una QToolBara que se crea cuando se llama a la función y que mostrará en pantalla la cadena que se pasa como  parámetro.

En la línea 16 inicializamos la etiqueta que será utilizada como widget central en la aplicación. Y en la línea 17 establecemos la fuente que queremos que ocupe la etiqueta, esto se hace mediante la instrucción:

QLabel::setFont(QFont(QString &fuente, int tamanio));

La cual recibe como parámetros un objeto QFont, el cual representa una fuente de texto y que a su vez recibe como parámetros el nombre de la fuente y el tamaño de la misma.

En la línea 19 inicializamos nuestra variable accionNuevo, del tipo QAction, mediante el constructor de la clase

QAction::QAction(QIcon(QString &archivo), QString &texto, QWidget* padre)

Este constructor recibe como parámetros un objeto QIcon, el cual representa un icono que se mostrará cuando la acción sea colocada dentro de una barra de herramientas y que a su vez recibe como parámetro una cadena de texto con la dirección dónde se encuentra el archivo de imágen que mostrará el icono, el segundo parámetro del constructor de la clase QAction es una cadena que indica el texto que se mostrará cuando la acción sea colocada dentro de una barra de menús y el último parámetro es el widget padre de la acción.

Antes de seguir debemos definir el concepto de QAction: Una QAction es una representación abstracta de un comando de la aplicación que puede ser ejecutado por el usuario.

En muchas aplicaciones los mismos comandos, acciones o funciones pueden ser ejecutados de diferentes maneras, ya sea mediante un elemento de la barra de menús, un icono de alguna barra de herramientas o una combinación de teclas, por mencionar algunos ejemplos. Una QAction nos es muy útil en este tipo de situación ya que puede estar asociada a múltiples widgets, gracias a esto será posible proporcionar la misma función en distintos lugares de la aplicación y de manera sincronizada, entonces podemos decir que una QAction proporciona una interfaz común para la ejecución de los comandos de la aplicación.

Siguiendo con el código, en la línea 20 establecemos un atajo de teclado para nuestra acción Nuevo, mediante la función

QAction::setShortcut(const QKeySecuence secuencia)

la cual recibe como parámetro un elemento de la enumeración QKeySecuence, dicha enumeración nos proporciona combinaciones estándar de teclas dependiendo de la configuración del sistema operativo en el que nos encontremos. Por ejemplo en el caso de mi sistemas operativo el elemento QKeySecuence::New esta relacionado con la combinación de teclas Ctrl+N sin embargo esto puede ser distinto en otro sistema operativo, pero al utilizar esta enumeración Qt se encargará de administrarlo y  en caso de que se requiera, asociarlo a otra combinación de teclas más adecuada en esa situación.

En la línea 21 establecemos el texto que deseamos que se muestre en la barra de estatus al posicionar el cursor del mouse sobre los widgets relacionados con la acción correspondiente. Esto se logra mediante la función:

QAction::setStatusTip(QString &texto)

La cual recibe como parámetro una cadena con el texto que deseamos mostrar.

En las líneas 23 a 33 realizamos lo mismo para las acciones restantes.

En las líneas 35 a 38 agregamos tres de las acciones que creamos al menú Archivo. Esto lo hacemos a través de la función

QMenu::addAction(QAction* accion)

Con el fin de lograr un diseñod e interfaz de usuario más claro y atractivo en la línea 37 agregamos un separardor, utilizando la función

QMenu::addSeparator()

Un separador es una línea vertical u horizontal que separa las acciones que está colocadas dentro del mismo menú o barra de herramientas pero que pueden ser ubicadas en una categoría específica o diferente del resto de las acciones del mismo menú o barra de herramientas.

En la línea 40 agregamos la acción AcercaDe al menú Ayuda.

En las líneas 42 a 45 agregamos las acciones a la barra de herramientas de la aplicación utilizando las mismas funciones que utilizamos para agregarlas a los menús.

En la línea 48 creamos la barra de estatus mediante la función

QMainWindow::statusBar()

La cual funciona de manera muy similar a las funciones utilizadas para crear las otras barras de la ventana principal, es decir, creará una barra de estatus para la ventana la primera vez que es llamada.

En la misma línea utilizamos la función

QStatusBar::showMessage(QString &mensaje)

para mostrar un mensaje en la barra de estatus, en este caso mostramos la palabra “Listo” con el fin de indicar que la aplicación puede comenzar a utilizarse.

En las líneas 52 y 53 conectamos la acción accionNuevo con su slot correspondiente, esto lo realizamos mediante la función connect(), la cual revisamos a detalle en un artículo anterior. Debido a que una acción puede estar asociada a múltiples widgets no siempre será lanzada de la misma forma, debido a ello Qt nos proporciona la señal triggered() (lanzada o disparada) la cual se emitirá cada vez que un widget asociado a la señal sea activado, por ejemplo un clic sobre un botón lanzará una acción asociada al mismo mientras que una combinación de teclas lanzará dicha acción al ser presionada por el usuario.

En las líneas 55 a 62 conectamos las acciones restantes a sus respectivos slots.

En la línea 65 comienza la implementación de los slots, los slots accionNuevoLanzada y accionAbriLanzada cambiarán el texto que se muestra en la etiqueta utilizada como widget central y redimensionarán la ventana para ajustarla al nuevo texto mostrado. El cambio de texto de la etiqueta se realiza mediante la función

QLabel::setText(QString &texto)

la cual recibe como parámetro una cadena de caracteres con el texto que se desea mostrar.

El cambio de tamaño de la ventana se realiza mediante la función

QMainWindow::resize(QSize(int width, int height))

esta función recibe como parámetro un objeto QSize, el cual es una estructura que incluye el ancho y alto de un widget y que a su vez recibe como parámetros dos enteros indicando el ancho y alto del widget, respectivamente.

También utilizamos la función sizeHint() la cual devuelve un objeto QSize con el tamaño requerido por el widget sobre el que se llamo la función.

En la línea 77 comienza la implementación del slot asociado a la acción acercaDe, en la línea 79 indicamos que al dispararse dicha acción se mostrará el conocido diálogo acerca de el cuál contiene información sobre la aplicación como versióno fecha de lanzamiento y sobre la compañia que creo la aplicación.

Finalmente en las líneas 82 a 85 implementamos el slot asociado a la acción salir, en la línea 84 utilizamos la función exit(int codigo) para indicar que deseamos salir de la aplicación, la aplicación devolverá un código el código de error indicado como parámetro. Normalmente un valor de cero indica que la aplicación termino normalmente, es decir, sin ningún error.

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "ventanaprincipal.h"
#include <QApplication>
 
int main(int argc, char* argv[])
{
    QApplication app(argc, argv);
 
    VentanaPrincipal* ventanaPrincipal = new VentanaPrincipal;
 
    ventanaPrincipal->show();
 
    return app.exec();
}

En la línea 1 incluimos el archivo de cabecera de la clase VentanaPrincipal, mientras que en la línea 8 creamos e inicializamos un objeto de dicha clase, y finalmente en la línea 10 mostramos nuestra ventana principal.

Al ejecutar esta aplicación de ejemplo obtendremos algo parecido a lo mostrado en las siguientes imagenes:

VentanaPrincipal-Inicio

VentanaPrincipal-NuevoSeleccionado

VentanaPrincipal-NuevoPresionado

VentanaPrincipal-AcercaDe

Es todo en este artículo, en la siguiente parte del tutorial veremos como implementar un widget personalizado, el cual podremos utilizar en futuras aplicaciones que desarrollemos.

Tutorial de Qt 4: Signals y Slots, implementando la funcionalidad de la aplicación

PésimoMaloRegularBuenoExcelente (2 votes, average: 4.50 out of 5)
Loading ... Loading ...

En la parte anterior de este tutorial vimos como utilizar layouts para diseñar la interfaz gráfica de nuestras aplicaciones y para ejemplificarlo diseñamos un diálogo de inicio de sesión.

En esta parte del tutorial aprenderemos a implementar la funcionalidad de nuestras aplicaciones utilizando Señales y Slots, los cuales forman el mecanismo a través del cual los objetos de una aplicación de Qt (incluyendo widgets) se comunican. Este mecanismo es una de la características distintivas de Qt, ya que otros frameworks suelen utilizar un enfoque basado en callbacks.

Una señal es una notificación que un objeto emite cuándo cambia su estado de manera que podría interesarle a otros objetos. Un slot es una función que se ejecuta cuándo una señal se emite.

Cualquier objeto en el que deseemos implementar señales y slots debe de heredar de la clase QObject, los widgets que utilizaremos normalmente cumplen con esto ya que heredan de QWidget que a su vez hereda de QObject. Los widgets que nos proporciona Qt poseen señales y slots predefinidos, pero también es posible crear un widget personalizado con el fin de añadir nuestras propias señales y slots.

A continuación mostramos el código de nuestra aplicación de inicio de sesión, en el cuál utilizamos señales y slots para implementar su funcionalidad, esto es que al capturar un nombre de usuario registrado y su contraseña correspondiente se nos permita el acceso a una sección restringida de una aplicación y que al capturar un nombre de usuario no registrado o una contraseña no coincidente se niegue el acceso.

En este ejemplo utilizaremos dos señales y dos slots, recordemos que las señales se emiten cuándo un objeto cambia de estado de manera interesante para otros objetos, en este caso serán emitidas cuando se presione alguno de los botones; Cada una de estas señales está conectada a un slot diferente, el cual se ejecuta cuando el botón respectivo es presionado. Más adelante veremos el código de estos slots.

En esta ocasión nuestra aplicación se compone de tres archivos, un archivo de definición de la clase, uno de implementación y un archivo main, definimos una nueva clase debido a que necesitamos un diálogo personalizado para implementar el slot que se ejecutará cuándo se presione el botón Aceptar en nuestra ventana de login, el slot que se ejecuta cuando se presiona el botón cancelar (close() el cual cierra la ventana) ya está predefinido.

NOTA: Sólo revisaremos a detalle las secciones que no hayan sido explicadas en partes anteriores del tutorial o que sean relevantes para esta explicación

El contenido de login.h, el archivo de definición de clase, es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <QDialog>
 
class QPushButton;
class QLineEdit;
 
class Login : public QDialog
{
    Q_OBJECT
 
public:
    Login();
 
private slots:
    void verificar();
 
private:
    QPushButton *botonAceptar, *botonCancelar;
    QLineEdit *campoUsuario, *campoPassword;
};
1
#include <QDialog>

En la línea 1 incluimos el archivo de cabecera de QDialog el cuál necesitamos debido a que nos basaremos en él para construir nuestro diálogo.

3
4
class QPushButton;
class QLineEdit;

En las líneas 3 y 4 indicamos al compilador que utilizaremos las clases QPushButton y QLineEdit, pero no especificamos sus detalles, los cuales se encuentran en sus archivos .h propios, es posible hacer esto debido a que declaramos las variables como tipo apuntador y a que en este archivo sólo las definimos pero no las utilizamos. También hubiera sido posible incluir los archivos de cabecera pero el sólo indicar el nombre de las clases permite reducir el tiempo de compilación.

6
class Login : public QDialog

En la línea 6 definimos nuestra nueva clase, la cual tendrá el nombre de Login y heredará de QDialog.

8
    Q_OBJECT

En la línea 8 utilizamos una macro llamada Q_OBJECT la cual es necesaria en cada clase que utilice señales y slots. Esta macro define algunas funciones de instrospección utilizadas por otras funciones como connect() y es necesaria para que el código de Qt sea traducido por el compilador meta objeto (moc, por sus siglas en inglés) a código C++ estándar.

10
11
public:
    Login();

A partir de la línea 10 definimos las funciones y los miembros de nuestras clase. En la línea 11 definimos el constructor de nuestra clase.

14
    void verificar();

En la línea 14 definimos nuestro slot personalizado, el cual lleva por nombre verificar(), se ejecuta cuándo se presione el botón Aceptar y como su nombre lo indica se encarga de verificar que los datos ingresados sean correctos.

17
18
    QPushButton *botonAceptar, *botonCancelar;
    QLineEdit *campoUsuario, *campoPassword;

En las líneas 17 y 18 declaramos los widgets que utilizaremos en nuestra aplicación, dos campos de texto, uno para el nombre de usuario y otro para la contraseña y dos botones, uno para solicitar la verificación de los datos capturados y otro para salir, que sólo se provee por comodidad.

El contenido del archivo login.cpp es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include "login.h"
 
#include <QPushButton>
#include <QLineEdit>
#include <QFormLayout>
#include <QHBoxLayout>
#include <QMessageBox>
 
Login::Login()
{
    QFormLayout *layoutPrincipal = new QFormLayout;
    QHBoxLayout *layoutBotones = new QHBoxLayout;
 
    botonAceptar = new QPushButton(trUtf8("Aceptar"));
    botonCancelar = new QPushButton(trUtf8("Cancelar"));
 
    campoUsuario = new QLineEdit();
    campoPassword = new QLineEdit();
 
    layoutBotones->addStretch();
    layoutBotones->addWidget(botonAceptar);
    layoutBotones->addWidget(botonCancelar);
 
    layoutPrincipal->addRow(trUtf8("Usuario"), campoUsuario);
    layoutPrincipal->addRow(trUtf8("Contraseña"), campoPassword);
    layoutPrincipal->addRow(layoutBotones);
 
    setLayout(layoutPrincipal);
 
    connect(botonAceptar, SIGNAL(clicked()),
            this, SLOT(verificar()));
 
    connect(botonCancelar, SIGNAL(clicked()),
            this, SLOT(close()));
}
 
void Login::verificar()
{
    if(campoUsuario->text() == "programacion" && campoPassword->text() == "linux"){
        QMessageBox::information(this, "", trUtf8("Bienvenido a la aplicación"));
        emit exit(0);
    }
    else
        QMessageBox::warning(this, "", trUtf8("La combinación usuario/contraseña no es válida"));
}
1
#include "login.h"

En la línea 1 incluimos el archivo de definición de nuestra clase.

9
10
11
12
13
Login::Login()
{
    QFormLayout *layoutPrincipal = new QFormLayout;
    QHBoxLayout *layoutBotones = new QHBoxLayout;
    ...

En la línea 9 comienza la implementación del constructor de nuestra clase, en él inicializamos los widgets y layouts necesario para la aplicación y definimos la apariencia de nuestro widget de la misma forma que hicimos en la sección anterior del tutorial.

30
31
32
33
34
    connect(botonAceptar, SIGNAL(clicked()),
            this, SLOT(verificar()));
 
    connect(botonCancelar, SIGNAL(clicked()),
            this, SLOT(close()));

Las líneas 30 a 34 son las que presentan novedades. En ellas utilizamos la función:

connect(QObject *emisor, const char *signal,
        QObject *receptor, const char *slot,
        Qt::ConnectionType type=Qt::AutoConnection);

La función connect es la encargada de conectar o enlazar dos QObjects, recibe como parámetros un apuntador al QObject emisor de la señal de interés, un apuntador a un arreglo de caracteres que indica la firma de función de la señal que nos interesa monitorear, un apuntador al QObject receptor de la señal y otro apuntador a un arreglo de caracteres, esta vez con la firma de función del slot que se ejecutará cuándo se emita la señal indicada.

Las macros SIGNAL() y SLOT() son requeridas por el moc al indicar el segundo y cuarto parámetro, respectivamente. Es necesario que las firmas de las funciones indicadas en estas macros coincidan en sus parámetros. Con la excepción de que la señal indicada puede tener más parámetros que los requeridos por el slot, en este caso los parámetros adicionales son ignorados.

Al utilizar la función connect() se pueden presentar los siguientes casos:

  • Cada señal está conectada a un slot distinto. Este es el caso más simple y es el que utilizamos en este ejemplo, en él el slot que se ejeucta depende de la señal que se emite.
  • Más de una señal puede estar conectada a un slot. En este caso el slot se ejecutará cuándo se emita cualquiera de las señales conectadas a él.
  • Una señal puede estar conectada a más de un slot. En este caso todos los slots conectados a la señal en cuestión se ejecutarán cuándo dicha señal se emita, uno tras otro en un orden indeterminado.
  • Una señal puede estar conectada a otra señal. En este caso la señal indicada en el cuarto parámetro se emitirá al emitirse la indicada en el segundo parámetro.
37
void Login::verificar()

En la línea 37 comienza la implementación de nuestro slot personalizado, indicamos el tipo de dato de retorno, después la clase a la que pertenece seguido del nombre del slot y su lista de parámetros, en este caso no ningún parámetro es requerido.

39
40
41
42
43
44
if(campoUsuario->text() == "programacion" && campoPassword->text() == "linux"){
        QMessageBox::information(this, "", trUtf8("Bienvenido a la aplicación"));
        emit exit(0);
}
else
    QMessageBox::warning(this, "", trUtf8("La combinación usuario/contraseña no es válida"));

En la línea 39 verificamos que la información capturada en los campos de texto coincida con la información de algún usuario registrado, en este caso y para mantener la simpleza indicamos en el código un único usuario: programacion, y su contraseña correspondiente: linux. La función QLineEdit::text() devuelve una QString con el contenido del QLineEdit en cuestión, en este caso el nombre de usuario para campoUsuario y la contraseña para campo Password.

QString es una clase de Qt que representa una cadena de caracteres unicode y que nos proporciona funciones bastante útiles como concatenación, traducción o búsqueda y reemplazo de caracteres, entre otras.

En caso de que la información capturada sea correcta mostramos un mensaje de bienvenida o confirmación y cerramos esta ventana para mostrar la ventana principal, debido a que en este momento sólo tenemos una ventana entonces salimos de la aplicación. En caso de que la información capturada sea incorrecta mostramos un mensaje de aviso informando que hubo un error.

Los mensajes de bienvenida o error, son mostrados al usuario utilizando las funciones estáticas de la clase QMessageBox

StandarButton QMessageBox::information(QWidget *padre, const QString &titulo,
        const QString &mensaje, StandarButtons boton=Ok,
        StandarButton botonPredeterminado=NoButton)

Esta función la utilizamos para mostrar un diálogo como el siguiente:
LoginCorrect

StandarButton QMessageBox::warning(QWidget *padre, const QString &titulo,
        const QString &mensaje, StandarButtons botones=Ok,
        StandarButton botonPredeterminado=NoButton)

Esta función la utilizamos para mostrar un diálogo como el siguiente:
LoginFailed
Estas funciones permiten mostrar un diálogo para mostrar información relevante o hacer una pregunta al usuario y recibir una respuesta.

Estas funciones reciben como parámetros obligatorios: Un apuntador al QWidget padre, que en este caso es nuestra ventana de login lo cual indicamos con la instrucción this; Una cadena de texto que será el título del mensaje; Y una cadena de texto que aparecerá en el contenido del QMessageBox.
Y como parámetros opcionales: Un conjunto de valores de la enumeración StandarButtons, que representan los botones que la QMessageBox incluirá y un elemento de la enumeración StandarButtons el cual representa al botón por default de la QMessageBox, es decir, el cual cambiará su estado a presionado (emitirá la señal clicked()) al presionar la tecla enter, en caso de no especificar estos parámetros se seleccionará por defecto el botón Ok.

El contenido del archivo main.cpp es el siguiente

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <QApplication>
#include "login.h"
 
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
 
Login *login = new Login();
 
login->show();
 
return app.exec();
}
2
#include "login.h"

En la línea 2 incluimos el archivo de definición de nuestra clase Login.

8
9
10
Login *login = new Login();
 
login->show();

Y finalmente en la línea 8 creamos e inicializamos un objeto de nuestra clase login, el cual mostramos en la línea 10.

Puedes continuar con el tutorial de Qt 4 en el artículo QMainWindow, la ventana principal de la aplicación.

Tutorial Gtk+2: Widgets, Signals y Callbacks (o “como funcionan las cosas”)

PésimoMaloRegularBuenoExcelente (No Ratings Yet)
Loading ... Loading ...

En esta sección del tutorial revisaremos la forma en la que puede interactuar el usuario con Gtk+ esto se logra principalmente con 3 herramientas en la mayoría de las interfaces gráficas:

1.-Widgets (dispositivo, artilugio), esto es toda herramienta con la que pueda interactuar el usario de forma directa o indirecta, ejemplos de widgets son: botones, campos de texto, listas, tablas etc.

2.-Signals (señales), toda muestra de que el usario ha utlilicado un widget utilizando algún dispositivo de entrada como es el teclado o el mouse, ejemplos de señales son: clicks, apretar alguna tecla, mover el puntero del ratón sobre algún área concreta etc.

3.-Callbacks (call back=”devolver llamada”), son las funciones que unen las señales y los widgets bajo un mismo contexto y realizan alguna acción en concreto, al dar “click” sobre el “boton abrir” se ejecuta una callback que abre el diálogo de selección de archivo, reciben el nombre de callbacks, ya que el sistema se encuentra en continuo monitoreo de las señales que podrían manifestarse mientras la ventana esta activa, y cuando detectan alguna las callbacks “devuelven la llamada” al sistema ejecutando la orden deseada.

Sin más preámbulos el código de esta sección:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include  #include <gtk/gtk.h>
 
struct context{
   int i;
   GtkWidget* label;
}context;
 
static void aumenta( GtkWidget *widget,struct context* cntxt )
{
    cntxt->i++;
    const char* text=g_strdup_printf("#:%d",cntxt->i);
    gtk_label_set_text((GtkLabel*)cntxt->label,text);
}
 
static void destroy( GtkWidget *widget, gpointer   data )
{
    gtk_main_quit ();
}
 
int main( int   argc, char *argv[] )
{
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *box;
    struct context cntxt;
    cntxt.i=0;
 
    gtk_init (&argc, &argv);
 
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
    g_signal_connect (G_OBJECT (window), "destroy",
		      G_CALLBACK (destroy), NULL);
 
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
 
    button = gtk_button_new_with_label ("¡Presioname!");
    cntxt.label= gtk_label_new("#:0");
    box=gtk_hbox_new(FALSE,0);
 
    g_signal_connect (G_OBJECT (button), "clicked",
		      G_CALLBACK (aumenta), &cntxt);
 
    gtk_container_add (GTK_CONTAINER (window), box);
    gtk_box_pack_start(GTK_BOX(box),button,TRUE,TRUE,0);
    gtk_box_pack_start(GTK_BOX(box),cntxt.label,TRUE,TRUE,0);
 
    gtk_widget_show (button);
    gtk_widget_show(box);
    gtk_widget_show (cntxt.label);
    gtk_widget_show (window);
 
    gtk_main ();
 
    return 0;
}

Linea por linea:

1
2
3
4
5
6
#include  <gtk/gtk.h>
 
struct context{
   int i;
   GtkWidget* label;
}context;

Analizemos el código, al comenzar incluimos nuestras librerias de gtk, despues viene una pequeña estructura que son los elementos a modificar mediante la callback.

8
9
10
11
12
13
static void aumenta( GtkWidget *widget,struct context* cntxt )
{
    cntxt->i++;
    const char* text=g_strdup_printf("#:%d",cntxt->i);
    gtk_label_set_text((GtkLabel*)cntxt->label,text);
}

Nuestra callback principal todas las callback tienen la siguiente estructura soyunacallback(GtkWidget* widget,gpointer data) donde el primer parametro es el widget que recibio la señal y el segundo es un puntero con los datos que queremos utilizar dentro de la callback, en este caso nuestra estructura.

8
9
10
11
static void destroy( GtkWidget *widget, gpointer   data )
{
    gtk_main_quit ();
}

Otra callback, esta realiza la tarea de terminar nuestro proceso en forma (al contrario de la sección anterior donde habia que hacerlo desde consola) y se ejecuta cuando la ventana recibe la señal “destroy” y que se pueda dar de distintas formas, como hacer click en la X de la esquina superior derecha (por si no la encuentran), o apretar la combinación de teclas alt-f4.

20
21
22
23
24
25
26
27
28
29
30
int main( int   argc, char *argv[] )
{
 GtkWidget *window;
 GtkWidget *button;
 GtkWidget *box;
 struct context cntxt;
 cntxt.i=0;
 
 gtk_init (&argc, &argv);
 
 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

Inicio de nuestra funcion main, declaración de cuatro widgets y nuestra estructura e inicialización de la variable i y de window.

32
33
34
35
g_signal_connect (G_OBJECT (window), "destroy",
		      G_CALLBACK (destroy), NULL);
 
gtk_container_set_border_width (GTK_CONTAINER (window), 10);

Conexión de el Widget ventana, con la señal “destroy” y la callback homónima, el ultimo parametro como se verá mas adelante es el mismo “gpointer data” de la callback, la siguiente linea define el grosor del borde de la ventana.

37
38
39
 button = gtk_button_new_with_label ("¡Presioname!");
cntxt.label= gtk_label_new("#:0");
box=gtk_hbox_new(FALSE,0);

Inicialización de los widgets “button” y “label”, el ultimo de nuestra estructura, en la ultima linea se inicializa el Widget del tipo hbox, que nos permitira acomodar varios widgets dentro de nuestra ventana, tema que se explicará más ampliamente en la siguiente sección.

41
42
g_signal_connect (G_OBJECT (button), "clicked",
		      G_CALLBACK (aumenta), &cntxt);

Conexión del widget button con la señal “clicked” y la callback aumenta, aqui podemos ver como el úlitmo parametro es un apuntador a nuestra estructura.

44
45
46
    gtk_container_add (GTK_CONTAINER (window), box);
    gtk_box_pack_start(GTK_BOX(box),button,TRUE,TRUE,0);
    gtk_box_pack_start(GTK_BOX(box),cntxt.label,TRUE,TRUE,0);

Aqui agregamos el widget del tipo caja al contenedor ventana, y en lugar de utilizar la función gtk_container_add, se utiliza la funcion gtk_box_pack_start, se especificarán los parámetros de esta función en la siguiente sección dedicada a contenedores.

48
49
50
51
52
53
54
55
56
    gtk_widget_show (button);
    gtk_widget_show(box);
    gtk_widget_show (cntxt.label);
    gtk_widget_show (window);
 
    gtk_main ();
 
    return 0;
}

Se muestran todos nuestros widgets y se da comienzo a la función principal, la cual permite el “escuchar” si alguna señal ha sido emitida y ejecuta la callback adecuada según el caso.

Tutorial de Qt 4: Layouts, organización de los Widgets

PésimoMaloRegularBuenoExcelente (No Ratings Yet)
Loading ... Loading ...

En el ejemplo anterior realizamos nuestra primera aplicación en Qt, el clásico Hola Mundo, en el cual solamente creamos una etiqueta con el texto “Hola Mundo!” y la mostramos en pantalla. Utilizamos este enfoque debido a que realizamos un programa que sólo serviría de ejemplo, pero en él se pueden apreciar serias deficiencias, tal vez la más notoria es que sólo es posible utilizar un elemento de interfaz gráfica (widget) a la vez, el cual en nuestro caso fue una etiqueta.

En este artículo veremos la forma de solucionar esto: utilizando Layouts.

Los Layouts son objetos que nos permiten organizar los widgets dentro de una ventana, en Qt disponemos de los siguientes tipos básicos de Layouts:

  • QHBoxLayout
  • QVBoxLayout
  • QGridLayout
  • QFormLayout

A continuación describiremos brevemente estos layouts y mostraremos un ejemplo básico de su uso.

QHBoxLayout

Nos permite ordenar los widgets en filas, es decir, de manera horizontal.

QHBoxLayout

El código para crear una aplicación con un layout como el de la imagen anterior es el siguiente, explicaremos sólo las líneas de código que no hayan sido vistas a detalle en partes anteriores del tutorial:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <QObject>
#include <QApplication>
#include <QDialog>
#include <QHBoxLayout>
#include <QPushButton>
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    QDialog *ventana = new QDialog();
    QHBoxLayout *layout = new QHBoxLayout();
    QPushButton *boton1 = new QPushButton(QObject::trUtf8("Botón 1"));
    QPushButton *boton2 = new QPushButton(QObject::trUtf8("Botón 2"));
    QPushButton *boton3 = new QPushButton(QObject::trUtf8("Botón 3"));
 
    layout->addWidget(boton1);
    layout->addWidget(boton2);
    layout->addWidget(boton3);
 
    ventana->setLayout(layout);
    ventana->setWindowTitle("QHBoxLayout");
    ventana->show();
 
    return app.exec();
}

Las líneas 1 a 5 importan las bibliotecas necesarias para esta aplicación, QObject nos proveerá de la función trUtf8() necesaria para escribir cadenas con caracteres Unicode, en nuestro caso, caracteres propios del español como la ñ, o el acento (tilde).

QDialog es una clase que representa un diálogo de aplicación. Utilizamos un diálogo en lugar de una ventana principal buscando mantener la simplicidad del ejemplo. Un diálogo es una ventana mediante la cual el usuario y la aplicación se comunican. Algunos de sus usos son:

  • Informar al usuario sobre la ocurrencia de algún evento relevante como una notificación al terminar un proceso o un error al realizarlo.
  • Solicitar confirmación para realizar alguna acción como borrar o guardar un archivo.
  • Solicitar información, como la palabra a buscar en un diálogo de buscar y reemplazar.

QHBoxLayout es una clase que representa a nuestro layout horizontal. QPushButton es una clase que representa a un botón estándar.

11
12
13
    QDialog *ventana = new QDialog();
    QHBoxLayout *layout = new QHBoxLayout();
    QPushButton *boton1 = new QPushButton(QObject::trUtf8("Botón 1"));

En las líneas 11 a 13 creamos un nuevo diálogo, layout y botón mediante la sentencia new para ejecutar el constructor de cada clase, en este caso el constructor del botón es el único que recibe parámetros, este parámetro es una cadena de texto que contenga la etiqueta que debe mostrar el botón. Las líneas 14 y 15 crean los otros botones de la misma forma.

17
18
19
    layout->addWidget(boton1);
    layout->addWidget(boton2);
    layout->addWidget(boton3);

En las líneas 17 a 19 colocamos los botones dentro de nuestro layout mediante la función

addWidget(QWidget *widget, int stretch=0, Qt::Alignment aling=0)

Esta función recibe como parámetros un apuntador al widget que deseamos agregar, un entero que indica el indice de “flexibilidad” (stretch) del widget y un elemento de la enumeración Qt::Alignment, los últimos dos parámetros pueden omitirse y en caso de hacerlo se les asiga el valor de cero. El stretch indica la proporción de espacio disponible en el layout que el widget ocupará, es relativo al stretch indicado en los otros widgets que están dentro del layout, entre mayor sea el valor de stretch mayor será el espacio que ocupará el widget. La enumeración Qt:Alignment indica la alineación que tendrá el widget y puede tener los siguiente valores:

  • Horizontales: Qt::AlignLeft (izquierda), Qt::AlignRight (derecha), Qt::AlignHCenter (centrado horizontalmente), Qt::AlignJustify (justificado)
  • Verticales:Qt::AlignTop (superior/arriba), Qt::AlignBottom (inferior/abajo), Qt::AlignVCenter (centrado verticalmente)
  • Bidimensionales:Qt::AlignCenter (centrado horizontal y verticalmente)

Los widgets se colocan en el orden en que se ejecutan las instrucciones, de forma que en este layout el primer botón de izquierda a derecha (la dirección por default de este layout) es boton1 seguido de boton2 y por último boton3. Si queremos invertir el orden de los widgets podemos escribir las instrucciones en orden inverso o podemos indicar que nuestros widgets se añadan de derecha a izquierda con la instrucción

setDirection(QBoxLayout:RightToLeft)
17
18
    ventana->setLayout(layout);
    ventana->setWindowTitle("QHBoxLayout");

En la línea 17 establecemos nuestro layout como el principal de la ventana, es decir el que indicará como se muestran los widgets en esa ventana. Y por último en la línea 18 indicamos el título que queremos que muestre nuestra ventana, si no se especifica se utilizará el del nombre del archivo.

QVBoxLayout

Nos permite ordenar los widgets en columnas, es decir, de manera vertical.

QVBoxLayout

El código para crear una aplicación con un layout como el de la imagen anterior es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <QObject>
#include <QApplication>
#include <QDialog>
#include <QVBoxLayout>
#include <QPushButton>
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    QDialog *ventana = new QDialog();
    QVBoxLayout *layout = new QVBoxLayout();
    QPushButton *boton1 = new QPushButton(QObject::trUtf8("Botón 1"));
    QPushButton *boton2 = new QPushButton(QObject::trUtf8("Botón 2"));
    QPushButton *boton3 = new QPushButton(QObject::trUtf8("Botón 3"));
 
    layout->addWidget(boton1);
    layout->addWidget(boton2);
    layout->addWidget(boton3);
 
    ventana->setLayout(layout);
    ventana->setWindowTitle("QVBoxLayout");
    ventana->show();
 
    return app.exec();
}

Si lo comparamos con el ejemplo anterior del QHBoxLayout, lo único que cambia es que nuestro objeto layout ahora es de tipo QVBoxLayout, el resultado de esto es que los widgets ahora se organizan de acuerdo a las reglas de este layout, es decir, de arriba hacia abajo. Si queremos invertir el orden en que se agregan los widgets al layout utilizamos la instrucción

setDirection(QBoxLayout::BottomToTop);

QGridLayout

Nos permite ordenar los widgets a manera de tabla o rejilla.

QGridLayout

El código para crear una aplicación con un layout similar al de la imagen es:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <QObject>
#include <QApplication>
#include <QDialog>
#include <QGridLayout>
#include <QPushButton>
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    QDialog *ventana = new QDialog();
    QGridLayout *layout = new QGridLayout();
    QPushButton *boton1 = new QPushButton(QObject::trUtf8("Botón 1"));
    QPushButton *boton2 = new QPushButton(QObject::trUtf8("Botón 2"));
    QPushButton *boton3 = new QPushButton(QObject::trUtf8("Botón 3"));
 
    layout->addWidget(boton1, 0, 0);
    layout->addWidget(boton2, 0, 1);
    layout->addWidget(boton3, 1, 0);
 
    ventana->setLayout(layout);
    ventana->setWindowTitle("QGridLayout");
    ventana->show();
 
    return app.exec();
}

Nuevamente cambiamos el tipo de nuestro objeto layout, ahora será de la clase QGridLayout.

La forma de agregar los widgets a este tipo de layout es ligeramente distinta, ahora lo haremos mediante la función

addWidget(QWidget *widget, int fila, int columna, Qt::Alignment align=0);

Esta función recibe como parámetros un apuntador al widget que deseamos agregar, dos enteros que indican la fila y columna, respectivamente, de la celda sobre la cual queremos agregar el widget en cuestión y un valor de la enumeración Qt::Alignment. Las filas y columnas comienzan a contarse desde cero de tal manera que la primera celda en la esquina superior izquierda tiene la posición fila=0, columna=0.

17
18
19
    layout->addWidget(boton1, 0, 0);
    layout->addWidget(boton2, 0, 1);
    layout->addWidget(boton3, 1, 0);

En la línea 17 colocamos al primer botón en la celda definida por la intersección de la fila cero con la columna cero, es decir, posición 0,0. Luego colocamos al boton2 y boton3 en las celdas 0,1 y 1,0 respectivamente.

El espacio vacío en la celda 1,1 se genera debido a que el QGridLayout crea tantas divisiones de filas y columnas como el número máximo de filas o columnas que indiquemos, en este caso dos, debido a la existencia de las filas y columnas uno y cero. Por ejemplo, si añadieramos los botones al layout mediante las líneas

    layout->addWidget(boton1, 0, 0);
    layout->addWidget(boton2, 1, 1);
    layout->addWidget(boton3, 2, 2);

Obtendríamos el siguiente resultado:

QGridLayoutManyColumns

Sin embargo habrá que tener en cuenta que las filas o columnas extras no serán visibles a menos que establezcamos el alto/ancho mínimo de cada fila/columna o que coloquemos un widget en la fila/columna correspondiente, en este último caso (que es lo que ha ocurrido en los dos ejemplos anteriores) el QGridLayout asigna automáticamente el alto/ancho mínimo de esta fila/columna con un valor igual al mínimo requerido por el widget en cuestión. Podemos establecer el ancho mínimo de una columna y el alto mínimo de una fila con las funciones:

setColumnMinimumWidth(int columna, int anchoMinimo )
setRowMinimumHeight(int fila, int altoMinimo)

Por ejemplo si añadieramos los botones al layout mediante el siguiente código:

layout->addWidget(boton1, 0, 0);
layout->addWidget(boton2, 1, 1);
layout->addWidget(boton3, 3, 3);

Se crearían cuatro filas y cuatro columnas, es decir, una fila y columna más que en el ejemplo anterior, pero al ejecutar el programa obtendríamos el mismo resultado que se muestra en la imagen pasada. Esto ocurre debido a que aunque la fila y columna con el número dos existen, estas tienen un alto y ancho de cero ya que no hemos colocado ningún widget en ellas ni hemos establecido el tamaño mínimo para ellas. Pero si después de la línea dónde agregamos el último botón al layout añadimos las líneas:

layout->setColumnMinimumWidth(2, 60);
layout->setRowMinimumHeight(2, 20);

Obtendríamos el siguiente resultado:

QGridLayoutEmptySpace

QFormLayout

Nos permite ordenar los widgets de manera similar a la de formulario web, es decir, filas compuestas por un par de widgets, los cuales normalmente son una etiqueta y un campo de texto.

QFormLayout

El código para crear una aplicación con un layout como el de la imagen anterior es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <QObject>
#include <QApplication>
#include <QDialog>
#include <QFormLayout>
#include <QPushButton>
 
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
 
    QDialog *ventana = new QDialog();
    QVBoxLayout *layout = new QVBoxLayout();
    QPushButton *boton1 = new QPushButton(QObject::trUtf8("Botón 1"));
    QPushButton *boton2 = new QPushButton(QObject::trUtf8("Botón 2"));
    QPushButton *boton3 = new QPushButton(QObject::trUtf8("Botón 3"));
 
    layout->addRow(QObject::trUtf8("Botón 1:"), boton1);
    layout->addRow(QObject::trUtf8("Botón 2:"), boton2);
    layout->addRow(QObject::trUtf8("Botón 3:"), boton3);
 
    ventana->setLayout(layout);
    ventana->setWindowTitle("QVBoxLayout");
    ventana->show();
 
    return app.exec();
}

En este caso nuestro layout será del tipo QFormLayout y para añadir widgets utilizarermos la función

addRow(QLabel *etiqueta, QWidget *widget);

aunque también es posible utilizar la siguiente función sobre cargada, con el fin de evitar crear una etiqueta para cada uno de los widgets que deseeemos agregar:

addRow(const QString &amp;texto, QWidget *widget)
17
18
19
    layout->addRow(QObject::trUtf8("Botón 1:"), boton1);
    layout->addRow(QObject::trUtf8("Botón 2:"), boton2);
    layout->addRow(QObject::trUtf8("Botón 3:"), boton3);

En las líneas 17 a 19 agregamos los widgets al layout, utilizamos la versión sobrecargada de addRow() en la que el primer parámetro es una cadena de texto con el fin de ahorrar código, debido a que en este ejemplo no necesitamos que el texto de alguna fila cambie y por lo tanto no es necesario conservar un apuntador hacia las etiquetas. Este tipo de layout es muy útil, por ejemplo, en la creación de formularios para la solicitud de información (como un registro de usuarios o un formulario de comentarios) en dónde debemos de indicar que información debe de capturar el usuario en cada campo.

Layouts Anidados

Normalmente las aplicaciones que desarrollemos no tendrán una interfaz tan sencilla como para ser diseñadas utilizando sólo un layout, para organizar los widgets de maneras más complejas utilizamos layouts anidados, es decir, un layout dentro de otro. La función que nos permite anidar layouts depende del tipo de layout que estemos utilizando, para QHBoxLayout y QVBoxLayout la función es:

addLayout(QLayout *layout, int Qt::Alignment align=0)

Para el QGridLayout además debemos especificar la fila y columna de la celda dónde deseamos agregar el layout, de la siguiente forma

addLayout(QLayout *layout, int fila, int columna, Qt::Alignment align=0)

Para el QFormLayout se utiliza una función sobrecargada de addRow(), en una de las siguientes formas, dependiendo de la apariencia que deseemos lograr:

addRow(QLabel *label, QLayout *layout)
addRow(QString &amp;texto, QLayout *layout)

Está función recibe como parámetros un apuntador a la etiqueta que contiene el texto que describe al layout o simplemente una QString con ese texto y un apuntador al layout que deseamos agregar.

addRow(QLayout *layout)

Esta función recibe cómo parámetro un apuntador al layout que deseamos agregar.

A continuación mostraremos un sencillo ejemplo de anidación de layouts para crear una interfaz de usuario muy conocida: un formulario de inicio de sesión.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <QApplication>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QDialog>
 
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
 
QDialog *ventana = new QDialog();
QHBoxLayout *layoutUsuario = new QHBoxLayout();
QHBoxLayout *layoutContrasenia = new QHBoxLayout();
QHBoxLayout *layoutBotones = new QHBoxLayout();
QVBoxLayout *layoutPrincipal = new QVBoxLayout();
 
QLabel *etiquetaUsuario = new QLabel("Usuario");
QLabel *etiquetaContrasenia = new QLabel("Password");
 
QLineEdit *campoUsuario = new QLineEdit();
QLineEdit *campoContrasenia = new QLineEdit();
 
QPushButton *botonAceptar = new QPushButton("Aceptar");
QPushButton *botonCancelar = new QPushButton("Cancelar");
 
layoutUsuario->addWidget(etiquetaUsuario);
layoutUsuario->addWidget(campoUsuario);
 
layoutContrasenia->addWidget(etiquetaContrasenia);
layoutContrasenia->addWidget(campoContrasenia);
 
layoutBotones->addStretch();
layoutBotones->addWidget(botonAceptar);
layoutBotones->addWidget(botonCancelar);
 
layoutPrincipal->addLayout(layoutUsuario);
layoutPrincipal->addLayout(layoutContrasenia);
layoutPrincipal->addLayout(layoutBotones);
 
ventana->setLayout(layoutPrincipal);
 
ventana->setWindowTitle(QObject::trUtf8("Iniciar Sesión"));
ventana->show();
 
return app.exec();
}

Al ejecutar este código obtendremos una salida parecida a la siguiente imagen

LoginBoxLayout

En las líneas 1 a 7 incluimos los archivos de cabecera necesarios para desarrollar la aplicación, mientras que en las líneas 13 a 26 creamos los widgets que utilizaremos. En las líneas 28 y 29 colocamos los widgets del campo usuario en un QHBoxLayout, lo mismo hacemos para los campos de contraseña y para los botones. Con el fin de lograr una interfaz más agradable alineamos los botones a la derecha insertando un espacio en blanco al principio del QHBoxLayout mediante la instrucción

addStretch(int stretch=0);
38
39
40
41
42
layoutPrincipal->addLayout(layoutUsuario);
layoutPrincipal->addLayout(layoutContrasenia);
layoutPrincipal->addLayout(layoutBotones);
 
ventana->setLayout(layoutPrincipal);

A partir de la línea 38 agregamos en el layout principal (el cual es un QVBoxLayout) el layout que contiene los controles de usuario, seguido por el que contiene los controles de contraseña y por último el que contiene los botones y finalmente en la línea 40 establecemos el layout principal de nuestra apliciación.

Es posible diseñar una interfaz de usuario utilizando distintas combinaciones de layouts, es cuestión de tiempo y experiencia poder encontrar aquella que sea más fácil y rápida de crear o la que se adapte mejor a las necesidades de nuestra aplicación. Para el ejemplo anterior un mejor diseño (considerando que requiere menos líneas) puede lograrse utilizando un QFormLayout en lugar de los primeros dos QHBoxLayout. El código es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <QApplication>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QLineEdit>
#include <QPushButton>
#include <QDialog>
 
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
 
QDialog *ventana = new QDialog();
QHBoxLayout *layoutBotones = new QHBoxLayout();
QFormLayout *layoutPrincipal = new QFormLayout();
 
QLineEdit *campoUsuario = new QLineEdit();
QLineEdit *campoContrasenia = new QLineEdit();
 
QPushButton *botonAceptar = new QPushButton("Aceptar");
QPushButton *botonCancelar = new QPushButton("Cancelar");
 
layoutBotones->addStretch();
layoutBotones->addWidget(botonAceptar);
layoutBotones->addWidget(botonCancelar);
 
layoutPrincipal->addRow(QString("Usuario"), campoUsuario);
layoutPrincipal->addRow(QString("Password"), campoContrasenia);
layoutPrincipal->addRow(layoutBotones);
 
ventana->setLayout(layoutPrincipal);
 
ventana->setWindowTitle(QObject::trUtf8("Iniciar Sesión"));
ventana->setWindowFlags(Qt::Window);
ventana->show();
 
return app.exec();
}

Al ejecutar este código obtenemos una salida similar a la siguiente

QFormLogin

La cual tiene una apariencia muy similar a la del ejemplo anterior y que en mi opinión incluso se ve mejor, pero lo importante es que el número de líneas utilizadas se redujo un poco, pero es de suponer que en una aplicación de mayor tamaño el ahorro de líneas de código también será mayor.

Puedes continuar este tutorial en el artículo de Singals y Slots en el cual explicamos como agregar funcionalidad a una aplicación de Qt.

Tutorial de bash: Hola mundo en bash

PésimoMaloRegularBuenoExcelente (No Ratings Yet)
Loading ... Loading ...

Bash, es un shell de Unix (un interprete de ordenes, pues) creado para el proyecto GNU. En conjunto con otras utilidades propias también de GNU, bash es una herramienta realmente poderosa y que vale la pena conocer. Es particularmente útil cuando se quiere trabajar con archivos y carpetas, con texto o con algunas particularidades de nuestro sistema operativo y no se quiere repelar con las características de un lenguaje de programación en especifico en estos temas.

Se puede hacer, por ejemplo:
Un programa que baje el código fuente de una pagina que tiene listados los links de algo que queremos bajar, la lea, identifique y extraiga los links que nos interesan en un archivo, y los descargue con la posibilidad de reanudar su tarea, justo después del último archivo descargado…
Añadir o quitar lineas del código fuente de algún programa para distintos propósitos de programación indicados con parámetros…
Compilar y hacer pruebas en toda una carpeta de proyectos…
Guardar archivos binarios completos dentro del .sh y después extraerlos (esto es común en la instalación de programas)…
y un LARGUÍSIMO etc.

Aprender bash es un tema extenso pero no extremadamente difícil y accesible a todos, pues muy seguramente si tienes instalado GNU/Linux, ya cuentas con un interprete de Bash.
Aquí un código sencillo y sin chiste que puedes copiar en el editor de texto tu preferencia:

#!/bin/bash
echo "Hola mundo!!"

Así de fácil.
El nombre con el que debe se ser guardado, no tiene otra restricción que la nuestro SO imponga. Por convención, lleva el sufijo “.sh”
Ahora vamos al complejísimo linea por linea:

#!/bin/bash

Indica la dirección en donde se encuentra el interprete de bash que vamos a usar. Si sale un error como “Command not found.” es por que está mal (Más adelante se verá como corregir esto).
El “#” es el símbolo reservado para hacer comentarios y el “!” indica que esa linea es la dirección al interprete.

echo "Hola mundo!!"

“echo” es una de las utilidades de shell que imprime lineas de texto. Aquí puse comillas respetando una buena practica y por convención, pero el “Hola mundo!!” así como cualquier texto puede no llevarlas.

Solo falta hacer nuestro archivo ejecutable, lo cual es posible con el siguiente comando:

$ chmod +x mibash.sh

Para ejecutarlo, hay que escribir:

$ ./mibash.sh

El “./” es lo mismo que poner el directorio actual. De estar en algún otro lugar, debe ponerse la dirección completa (como cualquier archivo ejecutable en GNU/Linux):

$ /home/usuario/mibash.sh

¿Cómo saber donde está mi interprete?
Hay varias maneras:

$ which bash > mibash.sh

Este comando pone en un archivo la dirección del interprete predeterminado del sistema en el archivo “mibash.sh”. Es cuestión de ponerle un “#!” al principio y listo.

Se puede buscar tecleando:

$ sudo find ./ -name bash

Algunas de las locaciones comunes son las siguientes:

/bin/bash
/sbin/bash
/usr/local/bin/bash
/usr/bin/bash
/usr/sbin/bash
/usr/local/sbin/bash

Por ahora es nada todo.

Algunas cosas las vi en este sitio