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.




Artículos relacionados

Autor plugin: nessus

Share this post

  • Digg
  • Del.icio.us
  • StumbleUpon
  • Reddit

One Comment to “Tutorial de Qt4: Diálogos, comunicación con el usuario (Parte II)”

  1. [...] This post was mentioned on Twitter by Programación Linux. Programación Linux said: Nuevo artículo publicado: Tutorial de Qt4: Diálogos, comunicación con el usuario (parte II) http://goo.gl/Y1xc [...]

Leave a Reply