|
Curso básico
de programación en Visual Basic
Lección
30
Más
sobre creación de submenús
|
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.
|
¿Te extraña ver otra entrega tan
pronto?
Aprovecha y no te quejes... que ya llegarán nuevas
"lagunas"; aunque puede que no tantas... depende... o
dependerá del tiempo, ganas, inspiración y hasta motivación...
que hasta para escribir entregas sobre el Visual Basic hay que estar
motivado e inspirado... que no es tan sencillo esto de ponerse a
escribir cuatro chorradillas sobre un lenguaje... y sino, que se lo
digan al Guille...
En serio, esto de explicar, en la medida de lo posible, las cosas de
forma que hasta se entienda, es algunas veces complicado... aunque,
dicho sea de paso, algunas veces no lo consigo... pero... eso es lo
que hay, y como por ahora no recibo muchas quejas, pues... me
imagino que la cosa queda más o menos clara... aunque se que no
todo lo claro que a algunos le gustaría...
Quiero aclarar un par de cosillas,
para que no te entre la desesperación si no das pie con bola...
Desde hace algunas entregas, la versión de VB que hay que usar es
como mínimo la 4, (preferiblemente de 32 bits), aunque cada vez voy
dirigiéndome más a la versión 5, giro que sobre todo se notará
cuando empecemos con el tema de los módulos de clases y esas
cosillas orientadas a objetos; así que si tienes un VB anterior a
la versión 5, ve planteándote el conseguir una nueva versión... o
te perderás algunas cosillas interesantes. El que avisa...
Como viene siendo habitual desde
hace un par de entregas, esta también está "tecleada"
por la "güena" de Encarni, que ya ha terminado con los
manuscritos o garabatos que le di... así que, si tardo en
publicarlas, la culpa será sólo mía...
Hablando de publicar... de vez en
cuando recibo una petición de "autorización" para usar
estas entregas en diferentes sitios, tanto de Internet como para
"revistas" de colegios y esas cosillas, gracias a los que
lo hacéis y lo único que pido es que se "respete" el
contenido, es decir TODO el contenido, incluido los
"desvaríos" y chorradillas, como estas, que escribo... si
me entero de que no lo hacen... me voy a enfadar.
Ya está bien de tantas chorradas,
así que vamos a seguir con los menús que el tiempo apremia.
Antes de ver el código
"operativo" de las opciones que añadimos en la
entrega anterior, vamos a seguir aprendiendo cosas de los
menús, para tener los conceptos más claros, que al fin y al cabo
es lo que interesa.
Menús
que contienen menús
Aunque en nuestro pequeño editor no lo vamos a usar, veremos
cómo se crean opciones de menús que a su vez muestran otros
menús.
Para ello vamos a crear otra opción en el menú ficheros para
poder imprimir, pero que nos mostrará un par de opciones:
configurar la impresora además de la opción imprimir. El aspecto
de este menú sería el siguiente:

Para poder conseguir un menú dentro de otro menú no hay que
hacer nada especial… simplemente usaremos lo que hasta ahora hemos
visto: indentar opciones.
Ya viste que cuando queríamos mostrar las opciones de uno de los
menús principales, simplemente "desplazábamos" las
siguientes opciones hacia la derecha… pues esto mismo es lo que
hay que hacer… desplazar las nuevas opciones y el Visual Basic
sabrá que tiene que mostrarlas en otro menú.
Por tanto, cada vez que necesitamos mostrar un menú al hacer
"click" en una de las opciones de cualquier menú,
desplazaremos esas opciones hacia la derecha.
Vamos a verlo de forma práctica:
Muestra el formulario, haz que se muestre el "diseñador de
menús", posiciónate en la opción "Salir", pulsa en
el botón insertar y escribe en la descripción, (o caption), &Imprimir…,
en el nombre del menú escribe mnuFicImp, pulsa en
siguiente para que acepte lo que hemos escrito, para insertar una
nueva línea, pulsa en el botón insertar y escribe en el caption: &Selecionar
impresora… y mnuFicImpSelec en el nombre
del menú; antes de pulsar en siguiente, dale al botón con la
flecha hacia la derecha, en esta ocasión tendremos seis puntos
suspensivos delante de esta opción, (me refiero a la lista de
abajo), esto indicará que está dos niveles hacia la derecha, es
decir que tenemos un menú dentro de otro menú.
Ahora pulsa en los botones siguiente e insertar y escribe &Imprimir
y mnuFicImpImp, ya sabes dónde, para que esté en
el mismo nivel que Seleccionar Impresora, tendrás que pulsar en la
flecha que señala a la derecha... para que esté en el mismo nivel
de menús.
Si por casualidad ves que salen más puntos suspensivos de la
cuenta... pulsa en el botón con la flecha a la izquierda para
quitar la indentación que le hayas dado de más.
Cierra el diseñador de menús.
Muestra el formulario, si pulsas en el menú Ficheros y a
continuación en Imprimir..., verás que tenemos un nuevo menú, en
este caso con las dos opciones que hemos añadido, (ver la figura
anterior).
Así de fácil se crean los sub-menús o menús que se muestran al
seleccionar una opción de un menú.
Nota:
Cuando tienes opciones ya creadas y quieres insertar
nuevas opciones, hay que usar el botón Insertar, pero
la "indentación" que muestra es la misma que
tiene el menú en el que nos posicionamos antes de
insertar, por tanto tendrás que usar las flechas de
indentación para ajustar los niveles de menús.
|
Mostrar
menús emergentes (popupmenús)
Antes de ver el código para
esta utilidad, que realmente es lo de menús, ya que la intención
de la misma es ver cómo crear y manejar menús, vamos a ver cómo
hace que se muestre un menú emergente: de esos que se suelen
mostrar al pulsar el botón derecho del ratón.
Si estás usando Windows 95 o superior, habrás notado que las
cajas de texto ya incluyen las opciones habituales de edición,
nosotros no tendremos necesidad de codificar nada para tener
disponibles esa característica. Pruébalo. Ejecuta con F5 el
programa y pulsa en el textbox, verás que se muestra un menú
emergente. Pero ese menú es el del sistema, si queremos que se
muestre el nuestro habrá que escribir un par de líneas de código.
¿Dónde? En el evento MouseDown del textbox, por tanto escribe
esto:
Private Sub txtEditor_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
' Si pulsamos el botón derecho... (vbRightButton = 2)
If Button = vbRightButton Then
' Mostrar el menú de Edición
PopupMenu mnuEdit
' Si queremos mostrar en negrita uno de los menús,
' lo indicaremos en el quinto parámetro
'PopupMenu mnuEdit, , , , mnuEditor(cEdCopiar)
End If
End Sub
Ya vimos que uno de los parámetros del evento MouseDown estaba
el de saber que botón se está pulsando, por tanto usaremos ese
parámetro, que es Button, para saber si es el
botón derecho, (vbRightButton que tiene un valor igual a 2), y si
es así, mostramos nuestro propio menú. Para ello usamos la
instrucción PopupMenu, en el primer parámetro
indicamos el nombre del menú que contiene las opciones que queremos
mostrar, del resto de los parámetros, en principio sólo nos
podría interesar el último, que indica que menú debe mostrarse
seleccionado.
En nuestro caso el menú a mostrar es mnuEdit que es del que
cuelgan las opciones de este menú.
Con PopupMenu se puede usar cualquier menú, incluso si no está
visible. Esa característica se suele usar cuando queremos mostrar
menús en nuestra aplicación pero queremos que se muestren
solamente como menús emergentes, en otra ocasión veremos esto.
Una vez que un menú emergente se ha mostrado funciona de igual
manera que si no fuese emergente… se que es "lógico",
pero lo aclaro por si las moscas… es decir cuando se selecciona
una opción, se ejecuta el código que hayamos escrito en el evento
click de esa opción.
Un detalle, puede que al pulsar el botón derecho en el textbox,
no se muestre el menú emergente, casi con toda seguridad tendrás
que pulsarlo por segunda vez, si no recuerdo mal, esto no ocurría
con el VB4...
Teclas de acceso
rápido en los menús.
Ya te comenté que se pueden asignar teclas de acceso rápido a
las opciones del menú, no todas, pero casi… por ejemplo, no se
pueden asignar F10 ni Alt+F4, pero eso no es inconveniente, ya que
se pueden detectar de otra forma, aunque ahora mismo no es lo que
nos interesa…
¿Cómo se añaden estos accesos rápidos? Pues… con el
diseñador de menús… aunque también se puede hacer mediante
código. Pero vamos a usar el "diseñador".
A estas alturas ya debes saber cómo mostrar ese dialogo…
¿verdad? Pues muéstralo y vamos a añadir inicialmente ese tipo de
accesos a las opciones del menú de edición.
Selecciona la opción "Cortar", en el cuadro de
diálogo hay una lista con las teclas que podemos usar, (en inglés
es Shorcut), selecciona Ctrl+X de la lista
desplegable. Haz lo propio con Copiar (Ctrl+C), Pegar (Ctrl+V) y
Seleccionar todo (Ctrl+A), cierra el cuadro de diálogo y pulsa en
el menú edición, verás que se han añadido al Caption esas
teclas, pero no sólo están "mostradas", sino que si
ejecutas el programa verás que están operativas y que no es
necesario hacer nada extra... simplemente pulsar esas combinaciones
de teclas y se ejecutará el código asociado a esa opción del
menú.

Para comprobarlo, vamos a codificar la opción de seleccionar
todo:
Muestra el form y selecciona el menú edición, pulsa en cualquiera
de las opciones y se mostrará la ventana de código, (también
podrías haberla seleccionado directamente, pero así parece que
ibas a hacer otra cosa, je, je ), el código en este evento será el
siguiente:
Private Sub mnuEditor_Click(Index As Integer)
' Cuando se selecciona un elemento del menú Edición
' se entra en este evento, el índice nos indicará
' el elemento seleccionado.
' Existen unas constantes para usarlas en lugar del número,
' por si añadimos o quitamos algunos
Select Case Index
Case cEdDeshacer
'
Case cEdCortar
'
Case cEdCopiar
'
Case cEdPegar
'
Case cEdSeleccionarTodo
With txtEditor
.SelStart = 0
.SelLength = Len(.Text)
End With
Case cEdBuscar
'
Case cEdBuscarSig
'
Case cEdReemplazar
'
End Select
End Sub
Ejecuta la aplicación y escribe varias líneas en el texbox,
pulsa la tecla control y sin soltarla pulsa la tecla a, (esto como
habrás observado en otras ocasiones, se simplifica diciendo: pulsa
Ctrl+A), ¡y ya está! ¡todo el texto seleccionado!.
Por supuesto que también puedes ir al menú edición y clickear
en la opción seleccionar todo.
Te explico un poco el código que hace que seleccione todo el
texto:
Le indicamos que la posición de inicio del texto seleccionado sea
la primera posición: .SelStart = 0
Le indicamos que el texto seleccionado sea de igual longitud que
todo el texto que hay escrito: .SelLength = Len(.Text)
Si no hubiésemos usado el With txtEditor... End With, tendríamos
que haber especificado el nombre del objeto, el código sería este
otro:
'
Case cEdSeleccionarTodo
txtEditor.SelStart = 0
txtEditor.SelLength = Len(txtEditor)
Ahora vamos a codificar un par de opciones del menú edición, lo
vamos a hacer con código en Visual Basic; de eso se trata ¿no?,
aunque podríamos apoyarnos en llamadas al API de Windows, es decir:
usar funciones propias del Windows para hacerlo, pero por ahora lo
vamos a dejar, entre otras cosas para que sepas como funciona y
sobre todo como se accede al portapapeles, (ClipBoard), desde el
Visual Basic.
Como
acceder al portapapeles (ClipBoard)
Las opciones que estarán relacionadas con el portapapeles son:
Cortar, Copiar y Pegar; antes de codificar estas opciones en el
evento mnuEditor_Click, veamos cómo manipular el clipboard.
Los métodos que vamos a usar de este objeto son:
Clear para borrar el contenido del
portapapeles
GetText para recuperar el texto que haya
SetText para asignar un texto
GetFormat, para saber si el tipo de formato
está disponible en el portapapeles los tipos de formatos se
averiguan con las constantes predefinidas en el VB5:
vbCFLink vínculo DDE
vbCFText formato texto, el que a nosotros
nos interesa
vbCFBitmat formato bmp
vbCFMetafile formato wmf (metafile)
vbCFDib mapa de bits independientes del
dispositivo, habitualmente todos los gráficos soportan este
formato
vbCFPalette paleta de colores
vbCFRtf formato RTF (rich text)
GetData obtener los datos del portapapeles
SetData Asignar datos al portapapeles
Por ahora vamos a trabajar con los cuatro primeros métodos:
Con GetFormat, sabremos si hay algún texto en el
portapapeles, en caso de que así sea, al mostrar el menú,
habilitaremos la opción Pegar y si no hay texto la
deshabilitaremos. De igual manera habilitaremos o no las opciones de
Cortar y Copiar, pero en este caso comprobaremos si hay texto
seleccionado
¿Dónde se hace esto?
Todas estas comprobaciones se hacen en el evento click del menú
edición, (del que "cuelgan" las otras opciones), ya que
este evento se dispara cuando pulsamos en él y es entonces cuando
de muestran las opciones.
Private Sub mnuEdit_Click()
' Por defecto, las opciones están deshabilitadas
mnuEditor(cEdCortar).Enabled = False
mnuEditor(cEdCopiar).Enabled = False
mnuEditor(cEdPegar).Enabled = False
' Comprobamos si hay texto en el portapapeles
If Clipboard.GetFormat(vbCFText) Then
' Hay texto, habilitamos la opción de pegar
mnuEditor(cEdPegar).Enabled = True
End If
' Si hay texto seleccionado, habilitamos Cortar y Copiar
If txtEditor.SelLength Then
mnuEditor(cEdCortar).Enabled = True
mnuEditor(cEdCopiar).Enabled = True
End If
End Sub
Cuando muestres el menú de edición, seguramente
"notarás" cómo los item cambian de estado… pero eso es
lo menos importante, ya que lo que interesa es que estén
habilitados los que tengan que estarlo.
Ahora que hemos habilitado y/o deshabilitado las distintas
opciones de edición, vamos a usarlas.
Según vimos, el menú de edición está en un array y por tanto
comparten el mismo nombre de menú y según el índice, hará
referencia a uno u otro, para acceder a las distintas opciones,
usamos constantes...
'
'...
Case cEdCortar
' Copiamos el texto seleccionado en el portapapeles
Clipboard.SetText txtEditor.SelText
' y lo quitamos del textbox
txtEditor.SelText = ""
Case cEdCopiar
' Simplemenente copiamos el texto seleccionado en el portapapeles
Clipboard.SetText txtEditor.SelText
Case cEdPegar
' Ponemos en el textbox el texto que haya en el portapapeles
txtEditor.SelText = Clipboard.GetText()
'...
Para el caso de deshacer, podemos usar el API de
Windows, realmente para todas estas opciones también, e incluso no
necesitamos ni siquiera codificar nada, ya que el propio Windows se
encarga de hacerlo… pero lo pongo aquí para que sepas hacerlo ya
que puedes añadir otras opciones, como buscar, reemplazar, etc.
Usar
el API, para deshacer
La función del API para este menester es: SendMessage, la
declaración es esta: (aunque pueden existir otras con diferentes
parámetros)
Nota:
Esta declaración y el valor de las constantes que voy a dar son
para Windows de 32 bits, si quieres saber los valores y la
declaración para 16 bits, en la sección API de mis páginas lo
tienes... (esto es por si estás leyendo esta entrega desde otro
sitio distinto al de mis páginas)
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long
Ahora necesitamos unas constantes para las distintas
"tareas":
Para saber si se puede deshacer:
'
Private Const EM_CANUNDO = &HC6
Private Const EM_UNDO = &HC7
Y para el resto de las opciones que hemos visto sería de esta
forma:
Private Const WM_CUT = &H300
Private Const WM_COPY = &H301
Private Const WM_PASTE = &H302
Private Const WM_CLEAR = &H303
Private Const WM_UNDO = &H304
Para saber si se puede deshacer:
If SendMessage(txtEditor.hWnd, EM_CANUNDO, 0&, ByVal 0&) Then
mnuEditor(cEdDeshacer).Enabled = True
End If
Fíjate que el último parámetro tiene "antepuesto"
al valor CERO la palabra ByVal, esto es porque en la declaración
de la función se ha especificado como As Any.
Para deshacer, también usamos la misma función del API, pero en
este caso le indicamos que "deshaga":
'
Case cEdDeshacer
Call SendMessage(txtEditor.hWnd, WM_UNDO, 0, ByVal 0&)
Usar el API para Cortar, Copiar y Pegar:
Para los casos de Cortar, Copiar y Pegar, se usarían los
"mensajes" apropiados, es decir: WM_CUT, WM_COPY y
WM_PASTE.
En todos los casos, se usa el hWnd del txtEditor
para indicarle a la función de Windows, que debe operar sobre esa
"ventana", por tanto todas las operaciones se realizarán
en la ventana de la cual indicamos el "manejador" de
ventanas (handle), que el VB nos proporciona mediante la propiedad
de sólo lectura hWnd. Todos los controles que "actúan"
como ventanas, tienen la propiedad hWnd.
Como puedes comprobar no tiene nada extraño ni raro, es decir
que esto del API de Windows es como todo: para saber lo que hay que
hacer hay que saber cómo hacerlo… y esa es la intención de este
cursillo, intentar enseñarte a hacer cosas con el Visual Basic... e
incluso con cosas que no es Visual Basic propiamente dicho...
Vamos a ponerlo todo junto y veamos el código que tenemos hasta
ahora en el formulario:
'
'--------------------------------------------------------------------------
' Editor para el curso básico
' ©Guillermo 'guille' Som, 1998-99
'--------------------------------------------------------------------------
Option Explicit
' Constantes para el menú de Edición.
' Los valores se corresponden con el índice de mnuEditor
Const cEdDeshacer = 0
Const cEdCortar = 2
Const cEdCopiar = 3
Const cEdPegar = 4
Const cEdSeleccionarTodo = 6
Const cEdBuscar = 8
Const cEdBuscarSig = 9
Const cEdReemplazar = 10
' Función del API de Windows de 32 bits de múltiple uso
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long
' Constantes para saber si se puede deshacer y deshacer
Private Const EM_CANUNDO = &HC6
Private Const EM_UNDO = &HC7
' Las constantes para cortar, copiar, pegar, etc
Private Const WM_CUT = &H300
Private Const WM_COPY = &H301
Private Const WM_PASTE = &H302
Private Const WM_CLEAR = &H303
Private Const WM_UNDO = &H304
Private Sub Form_Resize()
'------------------------------------------------------------------
'NOTA:
' ScaleWidth y ScaleHeight devuelven el tamaño "interno"
' del form o control.
' Width y Height devuelven el tamaño externo del form o control.
'------------------------------------------------------------------
' Sólo cuando no esté minimizado el formulario
If WindowState <> vbMinimized Then
' Si esto no funciona, que de seguro no funcionará,
' tendrás que ponerlo en el picStatus_Resize
'lblStatus.Width = picStatus.ScaleWidth - 60
' Ajustar el tamaño del TextBox
'txtEditor.Width = ScaleWidth
' Ajustar el alto, hay que tener en cuenta el alto
' del picture
'txtEditor.Height = ScaleHeight - picStatus.Height
' Posicionar el textBox en la parte superior izquierda
'txtEditor.Move 0, 0
' Esto es lo mismo que lo anterior
txtEditor.Move 0, 0, ScaleWidth, ScaleHeight - picStatus.Height
End If
End Sub
Private Sub mnuEdit_Click()
' Por defecto, las opciones están deshabilitadas
mnuEditor(cEdDeshacer).Enabled = False
mnuEditor(cEdCortar).Enabled = False
mnuEditor(cEdCopiar).Enabled = False
mnuEditor(cEdPegar).Enabled = False
' Para saber si se puede deshacer:
If SendMessage(txtEditor.hWnd, EM_CANUNDO, 0&, ByVal 0&) Then
mnuEditor(cEdDeshacer).Enabled = True
End If
' Comprobamos si hay texto en el portapapeles
If Clipboard.GetFormat(vbCFText) Then
' Hay texto, habilitamos la opción de pegar
mnuEditor(cEdPegar).Enabled = True
End If
' Si hay texto seleccionado, habilitamos Cortar y Copiar
If txtEditor.SelLength Then
mnuEditor(cEdCortar).Enabled = True
mnuEditor(cEdCopiar).Enabled = True
End If
End Sub
Private Sub mnuEditor_Click(Index As Integer)
' Cuando se selecciona un elemento del menú Edición
' se entra en este evento, el índice nos indicará
' el elemento seleccionado.
' Existen unas constantes para usarlas en lugar del número,
' por si añadimos o quitamos algunos
Select Case Index
Case cEdDeshacer
Call SendMessage(txtEditor.hWnd, WM_UNDO, 0, ByVal 0&)
Case cEdCortar
' Copiamos el texto seleccionado en el portapapeles
Clipboard.SetText txtEditor.SelText
' y lo quitamos del textbox
txtEditor.SelText = ""
' Si usamos el API:
'Call SendMessage(txtEditor.hWnd, WM_CUT, 0, ByVal 0&)
Case cEdCopiar
' Simplemenente copiamos el texto seleccionado en el portapapeles
Clipboard.SetText txtEditor.SelText
' Si usamos el API:
'Call SendMessage(txtEditor.hWnd, WM_COPY, 0, ByVal 0&)
Case cEdPegar
' Ponemos en el textbox el texto que haya en el portapapeles
txtEditor.SelText = Clipboard.GetText()
' Si usamos el API:
'Call SendMessage(txtEditor.hWnd, WM_PASTE, 0, ByVal 0&)
Case cEdSeleccionarTodo
txtEditor.SelLength = txtEditor.SelLength = Len(txtEditor)
With txtEditor
.SelStart = 0
.SelLength = Len(.Text)
End With
End Select
End Sub
Private Sub mnuFicSalir_Click()
' Terminar el programa
Unload Me
End Sub
Private Sub picStatus_Resize()
' Sólo cuando no esté minimizado el formulario
If WindowState <> vbMinimized Then
' Aquí se ajustará el tamaño del label
' cuando cambie el del picStatus
lblStatus.Width = picStatus.ScaleWidth - 60
End If
End Sub
Private Sub txtEditor_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
' Si pulsamos el botón derecho... (vbRightButton = 2)
If Button = vbRightButton Then
' Mostrar el menú de Edición
PopupMenu mnuEdit
' Si queremos mostrar en negrita uno de los menús,
' lo indicaremos en el quinto parámetro
'PopupMenu mnuEdit, , , , mnuEditor(cEdCopiar)
End If
End Sub
Ya sólo nos queda codificar las opciones de Abrir y Guardar, que
veremos en la siguiente entrega y algunas opciones como buscar,
reemplazar, que no se si veremos en la siguiente o en otra...
Nos vemos
|
|