Curso Básico de Programación
en Visual Basic
Entrega
Veinticuatro: 10/Oct/98
por Guillermo "guille" Som
Si quieres linkar con las otras entregas, desde el índice lo puedes hacer
![]()
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 hubiesemos 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 envie 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 ó 315 a los
TextBoxes y 375 ó 405 a los CommandButtons.
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.
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
acostumbrarnos. 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 tuviesemos un array de Text1, hariamos 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 tuviesemos 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, hariamos 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 contartelo 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.
Guillermo
![]()
Ir a la entrega anterior (la 23)
Las páginas
del Curso Básico se han visitado:
veces desde el 3/Sep/97 04:15 GMT