Estaba dándome cabezazos contra la mesa el otro día porque no
conseguía hacer funcionar una expresión regular en el código de Acid
Rain sin encontrar la explicación. La situación me llevaba casi a la
decepción por haber olvidado toda esa teoría cuando se me ocurrió buscar
alguna web donde probar lo que hacía. Al
encontrarla me
di cuenta de que no era tan mentecato, algo fallaba ya que la expresión
regular funcionaba. Tan loco me estaba volviendo que decidí hacer una
aplicación en QT en donde testar de forma rápida las expresiones, ya que
con la que estaba trabajando realmente me costaba un poco llegar al
punto donde se evaluaba la expresión.
Y
así fue que me puse a hacer una aplicación muy parecida a la web que he
comentado antes. En poco más de cinco minutos la tenía hecha y se me
ocurrió que sería un buen ejemplo para iniciarse en QT. Es tan sólo un
poco más complicado que un "Hola mundo" y de paso se ve como utilizar
aspectos esenciales de QT Creator, signals/slots y cómo trabajar con la
disposición de los elementos en un formulario. ¡Vamos al tema!
Creando el proyecto
Lo primero será crear el proyecto eligiendo "QT C++ Project" y como subopción "QT GUI Application"
Ahora le damos un nombre apropiado a la aplicación y apretamos sobre "Next"
Como se nos crea un formulario, debemos definir su nombre y el de la clase asociada al mismo
En cuanto a la creación del proyecto sólo nos queda aceptar el resumen.
Lo que queremos hacer
Lo
que nos interesa es tener un texto sobre el que queremos hacer alguna
prueba, usando una expresión regular para reemplazar parte del él por
otro texto determinado. Así pues necesitaremos unos cuantos campos
etiqueta, tres campos de entrada y uno de salida.
Los campos de
de entrada serán: el de la expresión regular, el de la cadena que
queremos introducir y el del texto inicial sobre el que trabaja. Para
los dos primeros campos nos bastará con un "line edit" mientras que para
el texto usaremos un "text edit". El resultado lo mandaremos a otra
caja de texto ("text edit") de salida que tendrá marcada la propiedad
"read only".
En cuanto le demos al botón "Test" se evaluará la
expresión regular y, para hacerlo mas emocionante y poder probar más
rápido nuestras expresiones, también se evaluará con cada cambio que
hagamos en el campo de entrada de la expresión, con lo que veremos los
resultados al vuelo mientras la escribimos.
En cuanto a la
disposición de los elementos, usaremos dos frames para agrupar por un
lado los campos del formulario y por otro el botón "Test".
Insertando los elementos de la ventana
Lo primero que haremos será insertar los dos frames, arrastrándolos a la ventana.
Lo
segundo debe ser elegir la disposición de la ventana (hay que
asegurarse de que está seleccionada), en este caso le daremos una
disposición vertical "Layout vertically"
Es
el momento de darle vida a todo esto. En el marco superior dejamos caer
cuatro campos "label", los dos "line edit" y los dos "text edit"
Ahora
hay que seleccionar el marco superior y después pinchar sobre "Lay out
in a form layout". Todavía no quedará muy bonito asi que habrá que
corregir la posición de los elementos. También podemos redimensionar un
poco el formulario haciendo uso del ratón para que no quede todo tan
ahogado en cuanto espacio.
Vamos con el marco inferior: hay que
añadir un "Push Button", después seleccionar "layout horizontally" para
el marco y finalmente añadirle un espaciador horizontal.
El
siguiente paso es cambiar el texto que muestran las etiquetas y el
botón y darle un nombre correcto a cada uno de ellos para que sea más
intuitivo utilizarlos desde el código. Los nombres podrían ser estos
(según el orden del formualrio):
lblRegEx | leRegEx
lblReplace | leReplace
lblText | teText
lblResult | teResult
pbTest
Aprovecharemos para seleccionar teResult y marcar la propiedad "read only"
Jugando con los slots
No
voy a entrar mucho en esto, tan solo una breve explicación. En QT la
comunicación entre objetos se hace mediante signals y slots. Por un
lado hay determinados eventos de los objetos que lanzan señales (al
hacer clic sobre un botón, al cambiar el texto en un campo de texto,
etc) Por otro lado los objetos también tienen asociadas una serie de
funciones llamadas slots cuya finalidad es ser receptoras de señales de
otros objetos ( por ejemplo setText(QString) en un campo text edit).
Uniendo ambas cosas podemos hacer que al hacer clic sobre un boton
"clear" se borre todo el contenido de una caja de texto.
Volvamos a
lo nuestro. Seleccionando el botón "Test", apretamos el botón derecho
de nuestro ratón para obtener el menú contextual y buscamos la opción
"Go to slot..."
Se
nos abrirá una ventana en la que elegiremos la señal clciked() y se nos
creará automáticamente la cabecera y el cuerpo vacío de un slot llamado
"on_pbTest_clicked". Internamente ya se ha relacionado la señal
"clicked" con el nuevo slot, así que sólo tendremos que añadir el código
que queramos al mismo (cosa que haremos luego) y este se ejecutará al
pinchar el botón en nuestra aplicación.

Lo
anterior sirve cuando es un objeto llamándose a si mismo, pero ¿cómo
hacemos algo similar entre dos objetos distintos? Pues ahora lo vemos,
recordemos antes que queríamos evaluar la expresión al vuelo mientras la
escribíamos así que vamos a relacionar la señal "textChanged" del campo
leRegExp con la ranura "clicked" del botón pbTest. Para ello nos vamos
al modo de edición "edit signals/slots" mediante f4 o haciendo uso del
botón de la parte superior de QT Creator. Una vez cambiado el modo,
arrastramos el ratón desde el campo de entrada hasta el botón y se nos
abrirá una nueva ventana de selección. En la izquierda escogemos la
señal "textChanged" y en la derecha el slot "click", aceptamos y los
tendremos ya relacionados. Esto quiere decir que cuando haya cualquier
cambio en la expresión regular será a todos los efectos, como si
pulsásemos el botón "Test" con lo que se irá evaluando al vuelo.
Un poquito de código
Bueno,
ya tenemos todo relacionado pero esto todavía no hace nade de nada.
Vamos a insertar el código, para ello abrimos el archivo
"regextextwindow.cpp" y buscamos la función que QT Creator nos ha
insertado. Bastará con dejarla así:
void RegExTestWindow
::on_pbTest_clicked
()
{
ui->teResult->setText(ui->teText->toPlainText().replace(QRegExp(ui->leRegExp->text()),ui->leReplace->text()));
}
Lo
que significa que asigne como texto del campo "teResult" lo obtenido al
reemplazar en el texto de prueba que hemos dejado en "teText" todo lo
que encaje con la expresión regular contenida en "leRegExp". Todo lo que
encaje con la expresión se sustituye por el valor de "leReplace"
¡Ya está!
Pues
si todo ha ido bien le damos al botón de ejecución y se nos lanzará la
apliación. Sólo nos queda desengrasar nuestros conocimientos en
expresiones regulares :)
Cuando tenga un rato colgaré el
código fuente y la aplicación en esta web para los más perezosos.
Sobre mi estupidez
Tal
vez os hayáis quedado pensando en lo que contaba al principio del post.
Resulta que cuando probé la expresión en la aplicación test la cosa
funcionaba. Así que tenía lo siguiente: funcionaba en la web, funcionaba
en el testador y fallaba en mi código. Cuando pasan cosas así siempre
piensas lo mismo "tiene que ser una estupidez como un piano"
Efectivamente así era, no se me había pasado por la cabeza el escapar el
carácter de escape, que perogrullada más infernal.
Una expresión valida como \s\d+/\d+\s escrita en código es \\s\\d+/\\d+\\s
Perder
tanto tiempo con una tontería semejante suele llevarme, cuando
encuentro la solución, al segundo pensamiento típico: "que empanado que
estoy"