Algunas de las cosas que más me gustan de las Qt… Extendiendo controles: Editando números.
Uno de los detalles que más me gustan de las librerías Qt es la posibilidad de extender controles de GUI fácilmente, gracias al mecanismo de Signals/Slots que tiene. Es cierto que con otros toolkits, existen las mismas posibildades, pero para mi gusto, el nivel de limpieza, claridad y elegancia de las Qt es muy destacado. Pongamos un ejemplo, vamos a crear un control básico de texto (un TextEdit de los clásicos) con posibilidades de editar números y formatearlos adecuadamente según el locale que deseemos. Para ello, extenderemos QLineEdit, el widget de edición de líneas de texto.
El archivo de cabecera, quedaría
------------------------------------------------------------------------------------------------
/***************************************************************************
* Copyright (C) 2007 by David Pinelo *
* david@pinelo.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef QPINELONUMEROEDIT_H
#define QPINELONUMEROEDIT_H
#include <QLineEdit>
#include <QWidget>
#include <QLocale>
#include <QString>
#include <QFocusEvent>
#include <QTextStream>
#include "generales/configuracion.h"
/**
Este texto será utilizado para presentar números en la aplicación.
El funcionamiento será el siguiente:
Cuando el objeto recibe el foco, eliminará el formato del número,
dejándolo solo como una sucesión de números en la parte entera y una
coma para separar la decimal. Cuando lo pierde, formatea el número
@author David Pinelo <david@pinelo.com>
*/
class QPineloNumeroEdit : public QLineEdit
{
Q_OBJECT
private:
/** Es posible establecer el número de decimales que deseamos visualizar en el control.
Lo hacemos con esta variable */
int numeroDecimales;
/** Esta variable, almacenará internamente el valor numérico del control */
double valorNumerico;
/** Variable chivato para evitar interacciones desagradables entre entrada de datos del
usuario y procesamiento interno */
bool bActualizandoTexto;
public:
QPineloNumeroEdit(QWidget * parent);
~QPineloNumeroEdit();
double getValorNumerico();
void setValorNumerico(double valor);
void setNumeroDecimales ( int theValue );
int getNumeroDecimales() const;
void focusInEvent ( QFocusEvent * event );
void focusOutEvent ( QFocusEvent * event );
public slots:
void clear();
protected slots:
void almacenarNumero(const QString &texto);
signals:
void textoCambiado(const QString texto);
void valorCambiado(double valor);
};
#endif
------------------------------------------------------------------------------------------------
La implementación, esto es, el .cpp, será tal que así
------------------------------------------------------------------------------------------------
/***************************************************************************
* Copyright (C) 2007 by David Pinelo *
* david@pinelo.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "componentesgui/qpinelonumeroedit.h"
QPineloNumeroEdit::QPineloNumeroEdit(QWidget * parent = 0)
: QLineEdit(parent)
{
// Capturamos la señal de texto cambiado, para almacenar siempre el valor numérico del editor.
connect (this, SIGNAL(textChanged(QString)), this, SLOT(almacenarNumero(QString)));
// Número de decimales que por defecto mostrará el control
this->numeroDecimales = 2;
// Inicialmente tendrá cero
valorNumerico = 0;
bActualizandoTexto = false;
setCursor(Qt::IBeamCursor);
setFocusPolicy(Qt::StrongFocus);
setAttribute(Qt::WA_InputMethodEnabled);
setAttribute(Qt::WA_KeyCompression);
setMouseTracking(true);
setAcceptDrops(true);
setAttribute(Qt::WA_MacShowFocusRect);
}
QPineloNumeroEdit::~QPineloNumeroEdit()
{
}
/**
\fn QPineloNumeroEdit::getValorNumerico()
Si en esta función accedemos al texto, utilizando text(), se pierde la posición del cursor
y la edición del número se hace imposible. Por eso, se ha creado una variable interna
que almacena el valor numérico, cada vez que el texto cambia. Aquí se devuelve ese valor
*/
double QPineloNumeroEdit::getValorNumerico()
{
return valorNumerico;
}
int QPineloNumeroEdit::getNumeroDecimales() const
{
return numeroDecimales;
}
void QPineloNumeroEdit::setNumeroDecimales ( int theValue )
{
numeroDecimales = theValue;
}
/**
\fn QPineloNumeroEdit::setValorNumerico(double valor)
Esta función presentará en el control, el valor pasado en el parámetro, para su edición
*/
void QPineloNumeroEdit::setValorNumerico(double valor)
{
bActualizandoTexto = true;
valorNumerico = valor;
if ( !hasFocus() ) {
setText (configuracion.getLocale()->toString(valor, 'f', numeroDecimales));
update();
}
bActualizandoTexto = false;
}
/**
\fn QPineloNumeroEdit::almacenarNumero(const QString & texto)
Si en cualquier función accedemos al texto, utilizando text(), se pierde la posición del cursor
y la edición del número se hace imposible. Por eso, se ha creado una variable interna
que almacena el valor numérico, cada vez que el texto cambia. Aquí se almacena ese valor
cada vez que se modifca el texto.
*/
void QPineloNumeroEdit::almacenarNumero(const QString & texto)
{
bool ok;
if ( !bActualizandoTexto ) {
if ( !texto.isNull() && !texto.isEmpty() ) {
// configuracion.getLocale() devuelve un objeto QLocale de Qt que contiene los métodos necesarios
// para tratar adecuadamente números, fechas, cadenas... acorde a un idioma.
valorNumerico = configuracion.getLocale()->toDouble(texto, &ok);
if ( !ok ) {
valorNumerico = 0;
}
}
}
emit textoCambiado(texto);
emit valorCambiado(valorNumerico);
}
/**
\fn QPineloNumeroEdit::focusInEvent(QFocusEvent * event)
Cuando el texto recibe el foco, se le eliminan todos los caracteres menos números y punto.
Es decir, mostramos en el texto, el numerito almacenado internamente, pero sin locale.
*/
void QPineloNumeroEdit::focusInEvent(QFocusEvent * event)
{
QString text;
bActualizandoTexto = true;
if ( valorNumerico == 0 ) {
text = "";
} else {
QTextStream (&text) << valorNumerico;
// Sustituimos el punto en valorNumerico por el caracter separador de decimales del local.
QChar separadorDecimales = configuracion.getLocale()->decimalPoint ();
text = text.replace('.', separadorDecimales);
}
setAlignment (Qt::AlignLeft);
setText (text);
// Además, seleccionamos todo el texto
bActualizandoTexto = false;
// Hay que llamar a este evento obligatoriamente.
QLineEdit::focusInEvent(event);
selectAll ();
}
/**
\fn QPineloNumeroEdit::focusOutEvent(QFocusEvent * event)
Cuando pierde el foco, se da formato.
*/
void QPineloNumeroEdit::focusOutEvent(QFocusEvent * event)
{
bActualizandoTexto = true;
if ( event->lostFocus() ) {
setText (configuracion.getLocale()->toString(valorNumerico, 'f', numeroDecimales));
setAlignment (Qt::AlignRight);
}
bActualizandoTexto = false;
// Hay que llamar a este evento obligatoriamente.
QLineEdit::focusOutEvent(event);
}
/**
\fn QPineloNumeroEdit::clear()
Limpieza absoluta del control
*/
void QPineloNumeroEdit::clear()
{
valorNumerico = 0;
QLineEdit::clear();
}
------------------------------------------------------------------------------------------------
Esta es una aplicación sencilla, básica y escrita rápidamente (el estilo es mejorable, la verdad), para tener un control de texto sencillo que permite editar números de tipo double con un valor de decimales preestablecidos.
Sin trackbacks por el momento.
