|
Curso básico
de programación en Visual Basic
Lección
24
Los
eventos producidos al pulsar teclas
|
Realizamos
programas para la gestión de empresas. Empresas medianas y
pequeñas. Programas de contabilidad, cartera de pedidos
clientes proveedores, facturación control de albaranes,
tesorería cartera de cobros y pagos y estadísticas.
Nuestro
agradecimiento a todos los que por unas causas o por otras
visitan nuestra web. Gestión de empresas PYMES. Curso de
programación de Visual Basic.
|
Son muchas las
cosas que ocurren en una aplicación mientras el usuario está
trabajando, (o cualquiera sabe lo que estará haciendo). Ya vimos
algunos eventos relacionados con el ratón, pero también habrá
muchos otros relacionados con el teclado, es decir, cada vez que
el usuario pulse una tecla se producirán varios eventos, que la
tecla se mantiene pulsada, que la tecla se ha soltado... en
resumen que la tecla se ha pulsado. También se puede saber cuando
una serie de teclas se pulsan al mismo tiempo, realmente cuando se
pulsan algunas de las "especiales": Shift, Ctrl o Alt.
Básicamente son
tres los elementos que la práctica totalidad de los controles y
formularios reconocen: KeyDown, KeyUp y KeyPress, vamos a verlos
por separado y con algo de detalle, además de algún ejemplo
aclaratorio.
Evento KeyPress.
Este evento se
produce cada vez que una tecla se pulsa, al menos una tecla
normal... ya que las teclas "especiales" no se
consideran normales y no se suelen detectar en este evento, salvo
que se use junto a una tecla "normal".
Veamos que información acepta
este evento como parámetro:
Private Sub Text1_KeyPress(KeyAscii As Integer)
El parámetro KeyAscii
nos indicará el código de la tecla pulsada, este código nos lo
da como valor numérico, no como una cadena, es decir que si
pulsamos la tecla A mayúscula, valdrá 65, ya que ese es el valor
ASCII de ese caracter, (realmente es un valor ANSI, pero...).
Para saber el valor de las teclas, puedes pulsar F2 en el IDE del
Visual Basic y buscar las constantes de KeyCode o en la ayuda
busca la palabra KeyCode, de todas formas los valores Ascii se
pueden saber o usar con la función ASC, por tanto se puede hacer
una comparación de este tipo:
If KeyAscii = Asc("A") Then
'se ha pulsado la A mayúscula
End If
En este evento se
pueden detectar un montón de teclas, todas las alfanuméricas y
otros caracteres, además de la tecla INTRO (return), aunque
tendrás problemas con la tecla TAB, ya que esta tecla tiene un
significado especial y no es tan fácil de detectar...
Normalmente se suele detectar la pulsación de la tecla INTRO,
entre otras cosas porque suele emitir un pitido cada vez que se
pulsa, al menos en las cajas de texto... para evitar ese
"pitido", se puede hacer esto:
If KeyAscii = vbKeyReturn Then
KeyAscii = 0 'Eliminamos el pitido
End If
Con esta
asignación, lo que hacemos es indicarle al VB que no se ha
pulsado nada... o al menos decirle que no tenga en cuenta que se
ha pulsado esa tecla.
Otra de las cosas
que se suele hacer cuando se pulsa INTRO es pasar al siguiente
control, de la misma forma que si hubiésemos pulsado la tecla
TAB, esto se suele hacer más a menudo de lo que parece, sobre
todo para usuarios que están acostumbrados a usar programas de
MS-DOS, para conseguirlo, además de tener "conectada"
la propiedad TabStop de los controles, (si esta propiedad tiene el
valor FALSE no se puede usar TAB para cambiar de control),
tendremos que decirle al Windows que lo que se ha pulsado no ha
sido el INTRO sino el TAB... es decir con algo como esto:
If KeyAscii = vbKeyReturn Then
KeyAscii = 0 'Eliminamos el pitido
'si queremos pasar al siguiente control
'tal como lo haríamos pulsando la tecla TAB:
SendKeys "{TAB}"
End If
Es decir, usamos
la instrucción SENDKEYS para que envíe una tecla TAB...
Para ver que teclas podemos "enviar" con SendKeys,
consulta la ayuda...
Por supuesto que
se pueden hacer muchas otras cosas en este evento, pero eso
dependerá de nuestra aplicación... y de nuestros gustos...
Eventos KeyDown y KeyUp.
Para tener un
mayor control en las teclas pulsadas, se suelen comprobar en los
eventos KeyDown y KeyUp, la principal diferencia con el evento
KeyPress es que en este caso no son códigos ASCII, sino códigos
de teclado...
Veamos los parámetros:
Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)
KeyCode
es el código de la tecla, no el código ASCII, aunque en la
mayoría de los casos coincide, aunque no en todos.
Shift es para saber si se ha pulsado al mismo
tiempo alguna de las teclas especiales: Shift (mayúsculas), Ctrl
o Alt.
El valor de las
teclas KeyCode se puede ver en la ayuda o pulsando F2, como te
indiqué antes, entre otras teclas, además de las normales, se
pueden detectar las teclas de función (F1, F2, etc), las teclas
de bloqueo de mayúsculas, bloque numérico, etc.
Los valores del parámetro Shift son los mismos que en el evento
del ratón, es decir: 1 para Shift, 2 para Control, 4 para Alt y
la combinación de estos valores, pásate por la
entrega anterior para ver
esos valores.
Debes tener en
cuenta que el evento KeyDown se produce cuando se presiona la
tecla y KeyUp cuando se suelta; según que casos, puede ser
interesante hacer las comprobaciones en uno u otro evento. Por
ejemplo, podrías hacer algún tipo de efecto cuando se pulsa la
tecla y otro diferente cuando se suelta...
Si quieres tener
un control sobre las pulsaciones de las teclas, puedes querer
comprobarlas de forma genérica antes de que sean enviadas al
control en el que se produce, hay una forma de hacerlo, para que
sea el formulario el que las reciba antes... Para ello deberás
asignar un valor TRUE a la propiedad KeyPreview
del formulario en cuestión. Ahora cada pulsación de teclas
serán procesadas primero por los eventos Keyxxx del formulario y
después por esos eventos del control que tenga el foco. Aunque si
un botón tiene asignada a TRUE la propiedad Default, no se
procesarán esas pulsaciones en el formulario.
Vamos a ver un
ejemplo para detectar la pulsación de la tecla ESC y si esta se
produce, mostrar un cuadro de diálogo que preguntará si queremos
terminar la aplicación... no es algo común hacer esto, pero en
algunas ocasiones puede ser interesante poder terminar una
aplicación al pulsar ESC, dónde utilizar esta forma de
"cerrar" un programa será cuestión tuya. Esto también
se consigue teniendo un botón con la propiedad Cancel = TRUE, si
ese botón se encarga de cerrar el programa, ya no tendrás que
hacer nada más... pero vamos a suponer que no tenemos ese botón
y queremos cerrarlo al pulsar ESC.
También veremos
cómo pasar al siguiente control cuando pulsemos INTRO; aunque
esto sólo será posible si tenemos asignada a TRUE la propiedad
TabStop de cada uno de los controles que estén en ese formulario.
Para este
ejemplo, vamos a crear un nuevo proyecto, automáticamente se
añade Form1. Ahora insertaremos varios controles, que realmente
no harán nada, pero así veremos cómo funciona todo esto. Veamos
añade 2 CommandButtons, 2 TextBoxes y un par de Labels.
Te voy a explicar
es cómo suelo "manejar" los controles cuando los
inserto en un formulario, que tamaños suelo usar, que posición,
etc. Normalmente suelo usar unos tamaños "predefinidos"
para los controles:
Los Labels suelo darles una altura de 255 ó 285 si tienen
borde, a los TextBoxes 315 y a los CommandButtons 375 ó 405.
El ancho dependerá del contenido que vayan a tener, en los
botones suelo dejarles el ancho por defecto: 1245
La separación de
los puntos del grid, los suelo tener definidos a 30x30 puntos. Es
decir que si muevo los controles o les cambio el tamaño, suelo
trabajar con valores de 30 puntos (¿twips?). Si quieres cambiar
el valor 120 que es el que tiene el VB por defecto, haz lo
siguiente:
Selecciona el menú Tools (Herramientas), te mostrará un cuadro
de diálogo, selecciona la solapa General, verás que hay una
serie de opciones para manipular el "grid" que se
muestra durante el diseño de los formularios. Si no has cambiado
nada, tendrás seleccionada las dos opciones que hay, en inglés
dice lo siguiente: (es que ahora tengo instalado el VB en inglés,
así que si la traducción que te doy no coincide con lo que te
muestra... intenta encontrarlas)
--Show Grid (Mostrar Grid o rejilla),
--Align controls to Grid (Ajustar los controles al grid)
También hay dos cajas de texto para indicar la separación de los
puntos mostrados en el grid, estos son los valores que tendrás
que cambiar.
Array de controles.
Aunque en las
aplicaciones simples no hay que preocuparse por los recursos que
usemos, no está de más acostumbrarse a aprovecharlos, así nos
será más fácil tomarlo como costumbre. Una forma de ahorrar
esos recursos del sistema es usando arrays de controles, al menos
siempre que sea posible. Por ejemplo los labels son unos controles
que nos permiten usar arrays sin demasiadas complicaciones, ya que
normalmente se suelen usar para poner título a las cosas y poco
más. En los casos en que uso los labels para mostrar
información, puede que no use un array, pero por regla general
uso arrays de labels.
Para crear un array de cualquier control, se puede hacer de la
siguiente forma: (esta es la que yo uso, porque entre otras cosas,
me mantiene los tamaños que le asigné)
Inserta un label, se creará Label1, seleccionalo, asigna el
tamaño que quieres que tenga, copialo, (pulsando el botón dereho
del ratón y seleccionando Copiar), ahora pulsa en cualquier parte
del formulario y selecciona pegar. Te preguntará si quieres crear
un array de Label1 (o el nombre que le hayas dado), dile que Si y
ya lo tienes creado.
La diferencia entre dos labels, (o cualquier otro control),
diferentes y dos que estén en un array es, entre otras, estas:
| |
Controles
diferentes |
Un
Array de Controles |
| Nombre |
Cada
una tendrá un nombre diferente: Label1, Label2, etc. |
Todas
tienen el mismo nombre, pero se debe usar un índice
para indicar a cual nos referimos.
Label1(0), Label1(1), etc. |
| Eventos |
Cada
control tendrá su propio juego de eventos. |
Todos
los controles comparten el mismo evento, pero ese evento
incluirá un nuevo parámetro que será el índice
dentro del array del control que lo ha producido. |
La ventaja de usar arrays es que sólo tienes que incluir código
en un sólo evento, ya que todos los controles en ese array
comparten el mismo "nombre". Pero aún así, cada uno de
los controles genera su propio evento. Para poder distinguirlos
hay que usar el índice del array, así si el evento lo ha
producido el que tiene el índice cero, el parámetro Index
valdrá cero.
Vamos a ver cómo se mostraría esos eventos en la ventana de
código:
Private Sub Label1_MouseMove(Index As Integer, Button As Integer, _
Shift As Integer, X As Single, Y As Single)
Los parámetros
son los mismos que si no estuviesen en un array, con la diferencia
de que ahora se incluye uno nuevo: Index.
Como te he comentado, éste parámetro es el que nos indicará el
control que ha recibido el evento. Para poder hacer cosas
diferentes según el control que sea, se puede usar una serie de If...Then
o Select Case...End Select, según tus gustos.
Por ejemplo, en el evento Click de un array de Labels:
Private Sub Label1_Click(Index As Integer)
'Para saber en que etiqueta se ha hecho click:
Select Case Index
Case 0
'Se ha hecho Click en el label de índice cero
Case 1
'Se ha hecho Click en el label de índice uno
End Select
End Sub
Esto mismo es
aplicable a los TextBox que tengan algún tipo de relación, la
ventaja, como puedes ver es que comparten los mismos eventos, en
algunos casos tendrás que saber el control que se está
procesando, pero en otros no, por ejemplo, si tienes un array de
TextBoxes y quieres que se seleccione todo el texto al recibir el
foco, esto se consigue añadiendo el siguiente código en el
evento GotFocus:
Private Sub Text2_GotFocus()
'Seleccionar el texto que haya en el Text2
'Si usamos With, es más cómodo codificar, ya que no hay
'que estar escribiendo el nombre del control.
With Text2
'Posición incial de la selección: cero, el primer caracter
.SelStart = 0
'Seleccionar todo el texto:
'esto se averigua con la longitud del contenido de la
'propiedad Text
.SelLength = Len(.Text)
End With
End Sub
Si tuviésemos un array de Text1,
haríamos lo mismo, pero simplemente cambiando el nombre del
control que ponemos después del With:
Private Sub Text1_GotFocus(Index As Integer)
'Seleccionar el texto que haya en el Text1(Index)
'Si usamos With, es más cómodo codificar, ya que no hay
'que estar escribiendo el nombre del control.
With Text1(Index)
'Posición incial de la selección: cero, el primer caracter
.SelStart = 0
'Seleccionar todo el texto:
'esto se averigua con la longitud del contenido de la
'propiedad Text
.SelLength = Len(.Text)
End With
End Sub
Fíjate que el
código usado es el mismo que para Text2. Si tuviésemos 20 cajas
de texto, tendríamos que repetir este código veinte veces, una
vez para cada control, pero al tener un array sólo habría que
ponerlo una vez.
Otra forma de no tener que repetir el código un montón de veces,
sería creando un procedimiento que hiciera ese trabajo. Veamos el
código para ese procedimiento:
Antes de ver el código, hay que saber que el procedimiento
necesita saber el control en el que se debe seleccionar, por tanto
necesitará recibir como parámetro un textbox... veamos el
código y espero que captes la forma de hacerlo:
Private Sub SeleccionarTexto(unTextBox As TextBox)
'Seleccionar el texto que haya en el TextBox
'Si usamos With, es más cómodo codificar, ya que no hay
'que estar escribiendo el nombre del control.
With unTextBox
'Posición incial de la selección: cero, el primer caracter
.SelStart = 0
'Seleccionar todo el texto:
'esto se averigua con la longitud del contenido de la
'propiedad Text
.SelLength = Len(.Text)
End With
End Sub
Como puedes
comprobar el código es el mismo que en los ejemplos anteriores,
lo único que se cambia es el nombre del control que está
después del WITH. El tipo de datos que se recibe como parámetro
es del tipo TextBox, ya que ese ese el tipo de control que vamos a
manipular, pero si se quisiera hacer más genérico y poder usarlo
con cualquier control que tenga una propiedad Text, podemos
cambiar el tipo de parámetro para que valga para cualquier
control:
Private Sub SeleccionarTexto(unTextBox As Contol)
De esta forma, lo
mismo dará usar un RichTextBox, un ComboBox o un control que
disponga de las propiedades usadas.
Para usar este
procedimiento, haríamos lo siguiente en el evento GotFocus de los
controles en los que queremos seleccionar al recibir el foco:
'Para el Text2:
Private Sub Text2_GotFocus()
'Llamamos al procedimiento, usando como parámetro
'el control Text2
SeleccionarTexto Text2
End Sub
'Para el array Text1:
Private Sub Text1_GotFocus(Index As Integer)
'Llamamos al procedimiento usando el Text1 correspondiente,
'en ese caso hay que indicar el índice.
SeleccionarTexto Text1(Index)
End Sub
En el caso del
Text1, que es un array, se pasa el TextBox que ha recibido el
foco: por tanto hay que indicarlo con el índice.
Bueno, vamos al
tema, que me estoy despistando un poco... aunque esto tenía que
contártelo algún día, así que tampoco ha venido mal del
todo... ¿verdad?
Para que un
formulario procese la pulsación de las teclas antes que los
controles, hay que asignar a la propiedad KeyPreview el valor
True. Haz click en el formulario, selecciona la ventana de
propiedades, (pulsa F4 si no está visible), busca la propiedad
KeyPreview y selecciona True ya que por defecto el valor es False.
Añade el siguiente código al código del formulario:
Private Sub Form_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyEscape Then 'Se ha pulsado ESC
'Descargamos el formulario
Unload Me
ElseIf KeyAscii = vbKeyReturn Then 'Se ha pulsado Intro
'Borramos la tecla pulsada para que no "pite"
KeyAscii = 0
'Enviamos una pulsación TAB
SendKeys "{TAB}"
End If
End Sub
Nota:
Lo de la pulsación del Intro no funcionará con los
botones ni con las cajas de texto que tengan un valor True en la
propiedad MultiLine, ya que el Intro se usa para cambiar de
línea.
El orden de
tabulación, es decir que control recibirá el foco cuando se
pulse la tecla TAB, estará indicado por el valor de la propiedad
TabIndex de cada uno de los controles. Ese valor se cambia de
forma automática cuando se modifica el valor de otro control. Al
principio tiene el valor según los controles añadidos, pero si
quieres cambiarlo, puedes modificar ese valor, sabiendo que el
primer control que recibirá el foco será el que tenga el valor
cero y después los que tengan el 1, 2, etc.
Las etiquetas no
reciben el foco, pero tienen esa propiedad, entre otras cosas, es
interesante que la tengan, ya que lo que hacen es pasar el foco al
control que tenga el valor siguiente dentro del TabIndex.
Normalmente se le suele dar a una etiqueta el TabIndex anterior al
textbox que tenga "asociado", o al que le está dando el
título, en caso de que esa sea su "utilidad".
Pero no podemos darle el foco a una etiqueta.
¿Entonces que utilidad tiene que tenga la propiedad TabIndex?
Que podemos usar una tecla de acceso rápido y si pulsamos esa
"tecla" el foco pasará al control siguiente.
Vamos a verlo con un ejemplo.
En el formulario habíamos añadido dos labels: Label1(0) y
Label1(1)
Selecciona la primera y escribe lo siguiente en la propiedad Caption:
&Nombre, comprobarás que la N está subrayada, pues
esa es la tecla de acceso rápido, para poder acceder a una tecla
de acceso rápido tendrás que pulsar Alt+tecla, en este caso
Alt+N.
Selecciona la otra etiqueta y asignale esto en el caption:
&Edad. Para poder usar este acceso rápido tendrás que pulsar
Alt+E.
Ahora vamos a poner en orden los
valores de TabIndex:
Supongamos que el formulario tiene este aspecto:

--Selecciona el
botón Aceptar, pulsa F4 para mostrar la ventana de propiedades,
busca TabIndex y escribe 0, pulsa Intro.
--Selecciona el botón cancelar, en la ventana de propiedades
seguirá estando seleccionada la misma propiedad, escribe de nuevo
cero.
--Haz lo mismo con el resto de los controles: LblInfo, Text2,
Edad, Text1, Nombre
Ahora el orden de
los valores de TabIndex será: Nombre, Text1, Edad, Text2,
LblInfo, Cancelar y Aceptar.
Pulsa F5 para
ejecutar el programa, el foco lo recibirá primero el Text1, el
cual se seleccionará. Si pulsas la tecla TAB verás que el foco
va cambiando a Text2, Cancelar y Aceptar, para volver a Text, etc.
Prueba pulsando Intro cuando estés en alguno de los TextBoxes y
verás que se cambia el foco al siguiente control.
Para terminar con
las pruebas, pulsa Alt+N y verás que el control que recibe el
foco es el Text1, después pulsa Alt+E y el que reciba el foco
será el Text2.
Bueno, creo que
ya está bien por hoy, no sea que te acostumbre a esto de las
entregas largas y no es cuestión.
En la siguiente entrega veremos algunos eventos más y con ello
concluiremos esta tanda, para pasar a ver algo sobre las
propiedades de los controles y algunas otras cosillas... como
adelanto, para tu tranquilidad, te diré que ya tengo
"manuscritas" tres entregas más y algunos
"esbozos" para otras cuantas... así que no te lo tomes
con demasiada calma que voy a seguir dándote la lata...
Hasta la próxima
que será, espero dentro de poco... porque como me retrase... no
será hasta entrado el mes de Noviembre, ya que me voy unos días
a Gran Canaria... así que... hazme
un poco la pelota si
quieres más entregas antes de que me vaya el próximo día 21...
je, je...
Nos vemos.
|
|