Un Gran Proyecto, Paso a Paso
Octava Entrega (20/Abr/97)
...pero lleg� la parienta y lo puso a
rematar la faena... �Se acab� el descanso!
(�por qu� siempre tendr�n las mujeres la culpa de todo?, me pregunto yo.)
Los links para conectar con las entregas anteriores y los archivos comprimidos est�n al final de la p�gina.
No ha pasado tanto tiempo, �verdad?
Es que creo que ser�a bueno poner un ToolBar y que se pudiesen soltar archivos de texto
en el cuadro de detalles.
Son chorradillas, pero dan otro "look & feel" al programa, vamos que parece
m�s "pofecion�"
Nota: A las "mar�as" que se
crean que es en serio el comentario del "subt�tulo"... que sepan que s�!!!
Y sino, que le pregunten a todos los "pepes" que pululan con la inform�tica...
Lo que no s�, es si al rev�s ocurre lo mismo... �Cual es la postura del
"t�o" frente a la "t�a" que le encanta la inform�tica?
A ver si alguna me lo dice...
Bueno, ya en serio (j�, j�, no caer� esa breva, �Guille!). A
partir de este punto, hay que manejar dos proyectos, uno para usarlo con los 32 bits y
otro para aquellos que deben usarlo en 16 bits. Hasta ahora val�a para ambos, siempre que
fuese con VB4.
Pero los controles al estilo Win95 (el ToolBar es uno de ellos) no se pueden usar en 16
bits y, que yo sepa, no hay un control equivalente, por lo menos que venga con los discos
del VB4.
Para aquellos que tengan el VB5, que sepan que deben usar la versi�n de 32 bits.
Para que el c�digo sea el mismo, s�lo cambiar� el form de gsNotas. El c�digo, salvo peque�os detalles, ser� el mismo. Lo que voy a plantear, de camino servir� para que le cojas un poca el "gustillo" y el "tranquillo" a las clases, ser� la creaci�n de una clase para la versi�n de 16 bits que se encargar� de simular al ToolBar de 32 bits, al menos en lo que a las llamadas se refiere. Espero conseguirlo.
1.- Unos ajustes en el form de Entrada, para usar la versi�n de 16 bits.
Entre otras cosas, al cargar el proyecto en el VB4 de 16
bits, antes no lo hab�a cargado, me he encontrado con que no encontraba el control de
di�logos comunes de 16 bits. Por tanto... he tenido que hacerlo casi manualmente, aunque
despu�s de intentarlo por segunda, o ser�a la tercera vez? ha aparecido...
Otro detalle, es el nombre del formulario "MostrarConsulta" no lo ha
encontrado!!! As� que le he cambiado el nombre por MostCons.frm, que al tener ocho
caracteres no da problemas.
Resumiendo: para usar el proyecto de 16 bits se usar�n los archivos gsNota16.frm y
Entrad16.frm y por supuesto el gsNot16.vbp
Pero vamos a los cambios gordos: Como los nombres de los
archivos pueden ser diferentes, a�n refiriendose al mismo, he optado por tener dos
versiones de "almacenamiento" de los datos en el archivo de configuraci�n, por
lo menos en cuanto a lo que el nombre de la base y el path se refiere. Esto s�lo lo he
puesto en el archivo de entrada de 16 bits, ya que la versi�n de 32 bits permanece
"inmutable", al menos en cuanto a este tema se refiere.
Te muestro el c�digo y la "l�gica" que he usado, por si te sirve, a ti que
usas la versi�n de 32 bits, al menos por curiosidad.
Esto estar� en Form_load:
'...
'Leer el n�mero de bases creadas
#If Win32 Then
numBases = Val(LeerIni(ficIni, "General", "NumeroBases"))
#Else
numBases = Val(LeerIni(ficIni, "General", "NumeroBases16"))
#End If
'Comprobar y leer los nombres
For i = 1 To numBases
'Si queremos usar m�s de 99 nombres, a�ade un cero m�s
#If Win32 Then
sNum = "Base" & Format$(i, "00")
#Else
'Si es 16 bits, usamos otro formato,
'porque puede ser la misma base, pero con nombre corto
sNum = "Base_" & Format$(i, "00")
#End If
sBase = Trim$(LeerIni(ficIni, "General", sNum))
'...
Esto estar� en cmdAceptar:
'...
'Esta base, hay que buscarla en las del usuario especificado
'el formato ser� usuarioXX=path_de_la_base
#If Win32 Then
sTmp = sUsuario & Format$(i + 1, "00")
#Else
sTmp = sUsuario & "_" & Format$(i + 1, "00")
#End If
'...
2.- Una barra de herramientas (ToolBar) para la versi�n de 32 bits.
Primero, lo primero... y es la versi�n de 32 bits...
aunque sea el segundo punto, es lo primero... o no?... no s�!
Ganas de cachondeo que tiene el ni�o...
Inserta los controles comunes de Windows. Pon un ImageList y un ToolBar. En el ImageList
inserta estos BMP en este orden:
nuevo, grabar, borrar, buscar, buscsig, impres, infow95, salir
En el Toolbar, asigna el ImageList para que apunte al ImageList1. Ahora inserta un bot�n
para cada uno de los gr�ficos que has incluido en el control de imagenes. Yo he puesto
unos separadores de esta forma:
Separador-Nuevo-Guardar-Borrar-Separador-Buscar-BuscarSiguiente-Separador-Consulta-Separador-AcercaDe-Separador-Salir
La imagen de la impresora para la consulta, s� que no es la m�s apropiada, pero...
Bien, ahora hay que hacer una serie de cambios, ya que los valores que ten�amos asignados a las constantes CMD_ no son los apropiados para los de los botones de la barra de herramientas. Deber�n quedar de esta forma:
'constantes para los botones de acci�n 'Seg�n el ToolBar Const CMD_Nuevo = 2 Const CMD_Actualizar = 3 Const CMD_Borrar = 4 Const CMD_Buscar = 6 Const CMD_BuscarSiguiente = 7 Const CMD_Consulta = 9 Const CMD_Acerca = 11 Const CMD_Salir = 13 ' Const CMD_Reemplazar = 105
Ahora hay que "actualizar" el tema de c�mo
llamar a estas acciones.
Como supongo que habr�s borrado el ToolBar con sus botones correspondientes, se habr�
quedado un Sub en la parte General, que se llamar� cmdAccion_Click, se puede dejar y lo
usaremos para las acciones que ya teniamos.
Lo que si tendremos que a�adir es una opci�n para Salir y otra para la consulta.
Salir, porque se hac�a por medio del cmdSalir, que NO habr� que borrar y consulta porque
s�lo se hac�a por medio del men�.
As� pues, a�ade esto en el Sub Accion, al final de los Case, antes del End Select:
Case CMD_Salir
cmdSalir_Click
Case CMD_Acerca
mnuAcercaDe_Click
Case CMD_Consulta
mnuConsulta_Click
Case Else
cmdAccion_Click Index
Si, el mnuAcercaDe no existe, ahora lo a�adiremos. Y
tambi�n sabr�s el porqu� de el Case Else.
Pero antes vamos a decirle al programa que sepa lo que tiene que hacer cualdo se pulse en
los botones de la barra de tareas.
A�ade este c�digo en el ToolBar1_ButtonClick:
Private Sub Toolbar1_ButtonClick(ByVal Button As Button)
Accion Button.Index
End Sub
Cuando se pulse en un bot�n, se manda al procedimiento Accion, si no se encuentra la acci�n indicada, se proceder� a buscar en cmd_Accion, por eso est� en el Case Else. �Lo entiendes ahora?
3.- Un Men� (y opci�n) para mostrar el Acerca De...
A�ade un nuevo men�, al final de los que ya est�n, que
sea como principal: Ayuda y como sub-men� Acerca De...
Puedes ponerle como short-cut F1 y como nombre para ejecutar la acci�n: mnuAcercaDe.
El c�digo a usar, ser�:
Private Sub mnuAcercaDe_Click()
'mostrar informaci�n del programa
'mostrar la informaci�n del programa, versi�n, etc.
Dim sMsg As String
With App
sMsg = vbCrLf
sMsg = sMsg & .EXEName & " v" & Format$(.Major, "00") & "." & _
Format$(.Minor, "00") & "." & Format$(.Revision, "0000") & vbCrLf & vbCrLf
sMsg = sMsg & .FileDescription & vbCrLf
sMsg = sMsg & .Comments & vbCrLf & vbCrLf
sMsg = sMsg & .LegalCopyright & vbCrLf & vbCrLf
sMsg = sMsg & .ProductName
End With
If MsgConfirm(sMsg, vbInformation, "Acerca de...") Then
End If
End Sub
4.- Habilitar/Dehabilitar los botones de la barra de tareas.
Ahora hay que hacer que los botones cambien de estado,
seg�n se hac�a antes cuando pulsabamos en nuevo, con idea de que no se pueda hacer otra
acci�n, salvo la de actualizar, Acerca de y Salir.
Tambi�n se deber�a hacer lo mismo con los men�s, as� que... si ves que no est� en el
c�digo del programa, hazlo.
Te doy una pista: Deber�as ponerlo en un sub-programa, para que sea m�s f�cil,
habilitarlos y deshabilitarlos.
'Deshabilitar los botones, excepto el de guardar
For i = CMD_Nuevo To CMD_Consulta
Toolbar1.Buttons(i).Enabled = False
Next
Toolbar1.Buttons(CMD_Actualizar).Enabled = True Case CMD_Actualizar
'Volver a habilitar los botones y poner la variable a False
For i = CMD_Nuevo To CMD_Consulta
Toolbar1.Buttons(i).Enabled = True
Next
Tambi�n deber�s borrar la l�nea que hac�a el focus en el bot�n de acci�n 0, en CargarTabla, cuando no hab�a datos:
'cmdAccion(0).SetFocus
5.- Las opciones de Copiar, Cortar, Pegar del men� de Edici�n, usando el API (se me hab�an olvidado, lo siento)
Pues si, se me habian olvidado por completo. Para estas
tareas, vamos a usar el API de Windows y echaremos mano a los trucos que puse para estas
tareas. As� ser� compatible con el men� desplegable del bot�n derecho del rat�n,
�espero!
Vamos a usar para estos casos la funci�n PostMessage, que es casi como SendMessage, pero
en teor�a, se supone que tambi�n en la pr�ctica, es m�s r�pida.
La diferencia entre SendMessage y PostMessage, es que la �ltima simplemente pone el
mensaje enviado en la cola de Windows y el valor devuelto es de si ha podido o no ponerla
satisfactoriamente en la susodicha cola.
SendMessage devolver�, en seg�n que casos, unos valores, una vez que se ha procesado el
mensaje enviado.
En el caso de Deshacer, ver�s que se usan las dos funciones y cada una tiene su cometido.
Aunque, como tambi�n indico, se podr�a usar en las dos ocasiones SendMessage.
Las declaraciones de las funciones del API y de las constantes son estas: (fijate que han
cambiado los valores de las constantes de edici�n con respecto a lo que te indicaba en
los trucos del API, estos valores los he probado y van bien, al menos en 32 bits.
He cambiado las opciones del men� de edici�n, de forma
que ahora sea un array, de esta forma ser� m�s r�pido, con un simple bucle, el tema de
habilitar o deshabilitar opciones, seg�n se trate o no de un textbox.
Y otras cosillas, para saber si se puede deshacer o pegar texto.
Estas declaraciones debes ponerlas en el m�dulo global: glbNotas.bas
'Funciones Globales del API
#If Win32 Then
Declare Function SendMessage Lib "User32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long
Declare Function PostMessage Lib "User32" Alias "PostMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
#Else
Declare Function SendMessage Lib "User" _
(ByVal hWnd As Integer, ByVal wMsg As Integer, _
ByVal wParam As Integer, lParam As Any) As Long
Declare Function PostMessage Lib "User" _
(ByVal hWnd As Integer, ByVal wMsg As Integer, _
ByVal wParam As Integer, lParam As Any) As Integer
#End If
'Declaraci�n de las constantes, para usar con SendMessage/PostMessage
Global Const WM_CUT = &H300
Global Const WM_COPY = &H301
Global Const WM_PASTE = &H302
'Global Const WM_CLEAR = &H303
'
Global Const EM_CANUNDO = &HC6
Global Const EM_UNDO = &HC7
Est�s son las constantes para las opciones del men� de
Edici�n, y los procedimientos.
Deber�s quitar los que hab�a antes. Fijate en las rutinas de la parte General del form,
averigua cuales quitar!
'Constantes para el men� de Edici�n
Const mEdDeshacer = 0
Const mEdCortar = 1
Const mEdCopiar = 2
Const mEdPegar = 3
Const mEdSep1 = 4
Const mEdBuscar = 5
Const mEdBuscarSiguiente = 6
Const mEdReemplazar = 7
Const mEdSep2 = 8
Const mEdBuscarActual = 9
Const mEdBuscarSigActual = 10
Const mEdReemplazarActual = 11
Const mEdSep3 = 12
Const mEdSeleccionarTodo = 13
Private Sub mnuEd_Click()
'Habilitar las opciones disponibles
Dim Habilitada As Boolean
Dim i As Integer
'los separadores no se pueden deshabilitar!!!
On Local Error Resume Next
'Asegurarnos que es un textbox
If TypeOf Screen.ActiveForm.ActiveControl Is TextBox Then
'ok, todo bien...
Habilitada = True
Else
'no poder hacer estas cosas
Habilitada = False
End If
For i = mEdDeshacer To mEdSeleccionarTodo
mnuEdicion(i).Enabled = Habilitada
Next
'Algunos chequeos para las opciones de edici�n:
If Habilitada Then
'Si no se puede deshacer, no habilitarlo
If SendMessage(Screen.ActiveForm.ActiveControl.hWnd, EM_CANUNDO, 0, ByVal 0&) Then
mnuEdicion(mEdDeshacer).Enabled = True
Else
mnuEdicion(mEdDeshacer).Enabled = False
End If
'comprobar si hay algo que pegar...
If Clipboard.GetFormat(vbCFText) Then
mnuEdicion(mEdPegar).Enabled = True
Else
mnuEdicion(mEdPegar).Enabled = False
End If
End If
Err = 0
On Local Error GoTo 0
End Sub
Private Sub mnuEdicion_Click(Index As Integer)
Select Case Index
Case mEdDeshacer
'-------------------------------------------------------------
' IMPORTANTE:
' En ambos casos se podr�a usar SendMessage,
' pero en el caso de EM_CANUNDO, NO servir�a PostMessage,
' porque esta funci�n s�lo devuelve un valor de
' si se ha puesto o no en la cola de mensajes de windows.
'-------------------------------------------------------------
'Si se puede deshacer...
'(aunque ya no es necesario comprobarlo, se supone que est� deshabilitado
'si no se puede deshacer, s�lo es a t�tulo explicativo, por el comentario anterior)
If SendMessage(Screen.ActiveForm.ActiveControl.hWnd, EM_CANUNDO, 0, ByVal 0&) Then
'Deshacerlo!
If PostMessage(Screen.ActiveForm.ActiveControl.hWnd, EM_UNDO, 0, ByVal 0&) Then
End If
End If
Case mEdCopiar
If PostMessage(Screen.ActiveForm.ActiveControl.hWnd, WM_COPY, 0, ByVal 0&) Then
End If
Case mEdCortar
If PostMessage(Screen.ActiveForm.ActiveControl.hWnd, WM_CUT, 0, ByVal 0&) Then
End If
Case mEdPegar
If PostMessage(Screen.ActiveForm.ActiveControl.hWnd, WM_PASTE, 0, ByVal 0&) Then
End If
Case mEdBuscar
cmdAccion_Click CMD_Buscar
Case mEdBuscarSiguiente
cmdAccion_Click CMD_BuscarSiguiente
Case mEdReemplazar
cmdAccion_Click CMD_Reemplazar
Case mEdBuscarActual
Accion CMD_BuscarActual
Case mEdBuscarSigActual
Accion CMD_BuscarSigActual
Case mEdReemplazarActual
Accion CMD_ReemplazarActual
Case mEdSeleccionarTodo
Accion CMD_SeleccionarTodo
End Select
End Sub
6.- La barra de herramientas (ToolBar) para la versi�n de 16 bits.
En la versi�n de 16 bits no podemos usar los controles de
Windows 95, as� que vamos a crearnos una barra de herramientas, esta est� m�s
conseguida que la que puse por ah� en el apartado de Novatos...
Vamos a usar el mismo picture en el que estaban los botones, si ya lo borrastes, s�lo
debes incluir un picture box con la propiedad BorderStyle a cero, sin borde y con el Align
a Top, inserta un array de 8 imagenes con Name = ImgTool, los �ndices de cero a siete.
Inserta un Shape (Shape1), y le asignas el �ndice a cero, y las dem�s propiedades se
asignar�n en el Form load.
A las imagenes, le asignas los bitmaps siguientes para las siguientes acciones (usa los
que pone ???95up), los otros no tienen la forma del bot�n. Las imagenes ser�n: Nuevo,
Grabar, Borrar, Buscar, BuscarSig (o Buscsi~1), Impresora, Info y Salir.
(los nombres no son estos, pero no creo que tengas problemas para reconocer los correctos)
Ahora s�lo queda asignar estas rutinas. Las clases la veremos en el siguiente apartado,
ya que se merecen un poco m�s de atenci�n.
'Para poder usar el recordset en 16 bits, cambia:
.Recordset.Terminada por .Recordset!Terminada
'En las declaraciones del Form:
'Para la simulaci�n del ToolBar
Dim Toolbar1 As New cToolBar
'En el Form_Load:
'...
'Asignar los valores a la colecci�n de Buttons del ToolBar
Dim i As Integer
'El Shape, lo usaremos para simular el Enabled=False
'es una chapuza, pero funciona!
With Shape1(0)
.DrawMode = 9
.BackColor = &HE0E0E0
.BackStyle = 1
End With
For i = 0 To 7
If i > 0 Then Load Shape1(i)
With imgTool(i)
Shape1(i).Move .Left, .Top
End With
Next
With Toolbar1
.Inicializar 1, CMD_Salir
.Buttons(CMD_Nuevo).ImgIndex = 0
.Buttons(CMD_Actualizar).ImgIndex = 1
.Buttons(CMD_Borrar).ImgIndex = 2
.Buttons(CMD_Buscar).ImgIndex = 3
.Buttons(CMD_BuscarSiguiente).ImgIndex = 4
.Buttons(CMD_Consulta).ImgIndex = 5
.Buttons(CMD_Acerca).ImgIndex = 6
.Buttons(CMD_Salir).ImgIndex = 7
End With
'Esta es la misma rutina que para 32 bits!
Private Sub Toolbar1_ButtonClick(ByVal Button As Button)
Accion Button.Index
End Sub
Private Sub imgTool_MouseDown(Index As Integer, Button As Integer, Shift As Integer, X As Single, Y As Single)
'Se ha pulsado...
If Button = 1 Then
imgTool(Index).BorderStyle = 1
End If
End Sub
Private Sub imgTool_MouseUp(Index As Integer, Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = 1 Then
Toolbar1_ButtonClick Toolbar1.Buttons(Toolbar1.Cual(Index))
imgTool(Index).BorderStyle = 0
End If
End Sub
Del resto de la tarea, se encargan las dos clases.
7.- Las clases para la simulaci�n del ToolBar, (me lo he currao, aunque no la vayas a usar, leetelo)
Estas son las clases que van a servirnos para simular el
ToolBar, sin tener que cambiar el c�digo usado por la versi�n de 32 bits, o sea que si
despu�s quieres cambiarte de 16 a 32 bits y le has hecho modificaciones al formulario,
s�lo tendr�s que quitar lo que se ha a�adido en el punto anterior... De nada.
Hay dos clases, una b�sica que es la que simular� el par�metro Button de los botones
del ToolBar. Y la otra ser� la que se encargue de manejar una colecci�n de este tipo.
Porque en el listado usamos la colecci�n Buttons para hacerlos disponibles (enabled) o
no.
Aqu� est�n las clases, creo que m�s o menos bien comentadas, as� que no creo que
necesites explicaci�n extra.
'---------------------------------------------------------------
'Clase para simular el tipo Button (20/Abr/97)
'
'(c)Guillermo Som, 1997
'---------------------------------------------------------------
Option Explicit
'Public Enabled As Boolean
Public Index As Integer
Public ImgIndex As Integer
Private sID As String
Public Property Get ID() As String
ID = sID
End Property
Public Property Let ID(vNewValue As String)
Static YaEstoy As Boolean
If YaEstoy Then Exit Property
sID = vNewValue
YaEstoy = True
End Property
Public Property Get Enabled() As Boolean
If ImgIndex <> -1 Then
Enabled = gsNotas.imgTool(ImgIndex).Enabled
End If
End Property
Public Property Let Enabled(vNewValue As Boolean)
If ImgIndex <> -1 Then
With gsNotas
.imgTool(ImgIndex).Enabled = vNewValue
.Shape1(ImgIndex).Visible = Not vNewValue
.Shape1(ImgIndex).ZOrder
End With
End If
End Property
'--------------------------------------------------------------
'Clase para simular el ToolBar (20/Abr/97)
'
'S�lo para usarlo con 16bits o para simular el ToolBar en 32bits
'
'(c)Guillermo Som, 1997
'--------------------------------------------------------------
Option Explicit
Private colButtons As New Collection
Public Function Buttons(ByVal Index As Integer) As Button
'Devuelve o asigna un elemento de la colecci�n
Dim tButton As New Button
Dim sIndex As String
On Local Error Resume Next
sIndex = "Button" & Format$(Index, "00")
Set tButton = colButtons(sIndex)
If Err Then
Set tButton = Nothing
With tButton
.ID = sIndex
.Index = -1
.Enabled = False
End With
Err = 0
End If
Set Buttons = tButton
On Local Error GoTo 0
Set tButton = Nothing
End Function
Public Function Cual(ByVal Index As Integer) As Integer
'Devolver el �ndice adecuado
Dim tButton As New Button
For Each tButton In colButtons
If tButton.ImgIndex = Index Then
Cual = tButton.Index
Exit For
End If
Next
End Function
Public Sub Inicializar(ByVal Primero As Integer, Ultimo As Integer)
'inicializa la colecci�n
Dim i As Integer
Dim tButton As New Button
Set colButtons = Nothing
For i = Primero To Ultimo
Set tButton = Nothing
With tButton
.ID = "Button" & Format$(i, "00")
.Enabled = True
.Index = i
.ImgIndex = -1
colButtons.Add tButton, .ID
End With
Next
End Sub
Y esto es todo, que no ha sido poco.
Espero que los "forofos" de los 32 bits no se hayan "aburrido" y que
los "pocos" de 16 bits, no se sientan ya desplazados.
De todas formas, si tienes alguna duda... pregunta, pregunta.
�Feliz programaci�n!
Nos vemos.
Entregas anteriores: Primera,
Segunda, Tercera, Cuarta, Quinta,
Sexta, Septima
Pues esta vez no te lo digo... No hace falta que eches un vistazo a las entregas
anteriores...
Bajate las p�ginas HTML y los gr�ficos de
las 7 primeras entregas. (gsnotas_htm.zip 84.3 KB)
(si es el mismo archivo, no se incluye esta entrega)
Para bajar
esta entrega y las posteriores, cuando haya. (gsnotas2_htm.zip 8.97 KB)
Bajate los
listados y los bitmaps para las barras de herramientas. (gsnotas.zip 53.6 KB)
(Estos tama�os variar�n seg�n el n�mero de entregas; para saber el tama�o actual,
deber�as ver la �ltima entrega)