Un Gran Proyecto, Paso a Paso

 

Segunda Entrega (1/Mar/97)

Pulsa aqu�, para ver la Primera Entrega
Nota: Deber�as verla, porque ha habido cambios


Antes de ver el c�digo del formulario de Entrada, necesitamos crear un m�dulo para las declaraciones globales. Inserta un nuevo m�dulo y guardalo como:glbNotas.bas
Ahora mismo s�lo necesitamos unas variables globales: el nombre del archivo de configuraci�n, el nombre del usuario y la base de datos, posteriormente incluiremos m�s cosas.

A�ade las siguientes l�neas:

'--------------------------------------------------------------
'glbNotas   M�dulo para las declaraciones globales  (28/Feb/97)
'--------------------------------------------------------------
Option Explicit

Global ficIni As String			    'Archivo de configuraci�n
Global sUsuario As String                   'Nombre del usuario actual
Global sBase As String                      'Nombre de la base

La raz�n de crear el archivo de configuraci�n como global, es que si quieres cambiar el nombre de este archivo, s�lo tendr�s que modificar una asignaci�n.

Ahora si podemos ver el c�digo del form de Entrada.

Private Sub Form_Load()
    Dim numBases As Integer
    Dim sBase As String
    Dim sNum As String
    Dim i As Integer
    
    'Archivo de configuraci�n en el directorio de la aplicaci�n
    ficIni = App.Path & "\gsNotas.ini"
    Combo1.Text = ""
    'Nombre del �ltimo usuario
    Text1 = LeerIni(ficIni, "General", "Usuario", "")
    'Leer el n�mero de bases creadas
    numBases = Val(LeerIni(ficIni, "General", "NumeroBases"))
    'Comprobar y leer los nombres
    For i = 1 To numBases
        'Si queremos usar m�s de 99 nombres, a�ade un cero m�s
        sNum = "Base" & Format$(i, "00")
        sBase = Trim$(LeerIni(ficIni, "General", sNum))
        If Len(sBase) Then
            'A�adir al combo, si no es una cadena vac�a
            Combo1.AddItem sBase
        End If
    Next
    'Si hay datos en el Combo, seleccionar el primero
    If Combo1.ListCount Then
        Combo1.ListIndex = 0
    End If
End Sub



Private Sub cmdAceptar_Click()
    Dim sPath As String                         'path de la base especificada
    Dim sUserPath As String                     'path del usuario
    Dim sUserBase As String                     'nombre de la base del usuario
    Const cMsg = "Seleccionar la base"          'Constante para los MsgBox
    Dim numBases As Integer                     'N�mero de bases
    Dim sTmp As String                          'varios usos
    Dim i As Integer                            'variable del bucle
    
    'Comprobar si hay datos introducidos
    sUsuario = Trim$(Text1)
    If Len(sUsuario) = 0 Then
        MsgBox "Debes especificar el nombre del usuario.", vbInformation, cMsg
        'Posicionarse en el Text1
        Text1.SetFocus
        Exit Sub
    End If
    sTmp = Trim$(Combo1.Text)
    If Len(sTmp) = 0 Then
        MsgBox "No hay ninguna base de datos seleccionada.", vbInformation, cMsg
        Combo1.SetFocus
        Exit Sub
    End If
    
    'Separar los datos del path y nombre del archivo
    SplitPath sTmp, sPath, sBase
    
    'Comprobar si la base existe en el combo
    '   Si no existe, a�adirla al combo
    i = ActualizarLista(sBase, Combo1)
    If i = -1 Then
        'Este caso seguramente nunca se dar�, pero...
        MsgBox "Se ha producido un error inesperado al a�adir al combo", vbCritical, cMsg
        Unload Me
        End
    End If
    
    'Esta base, hay que buscarla en las del usuario especificado
    'el formato ser� usuarioXX=path_de_la_base
    sTmp = sUsuario & Format$(i + 1, "00")
    sUserPath = Trim$(LeerIni(ficIni, "General", sTmp, sPath))
    sUserBase = sUserPath & "\" & sBase
    
    'Por si la ruta es err�nea
    On Local Error Resume Next
    
    'Comprobar si existe "fisicamente" la base
    If Len(Dir$(sUserBase)) = 0 Then
        'No existe, preguntar si se crea
        If MsgBox("La base especificada no existe." & vbCrLf & "'" & sUserBase & "'" & vbCrLf & "�Quieres crearla?", vbQuestion + vbYesNo, cMsg) = vbYes Then
            'Crear la base
            CrearBase sUserBase
        Else
            Combo1.SetFocus
            Exit Sub
        End If
    End If
    If Err Then
        MsgBox "Seguramente la ruta especificada, es err�nea:" & vbCrLf & "'" & sUserBase & "'", vbInformation, cMsg
        Combo1.SetFocus
        Exit Sub
    End If
    
    'Guardar los datos de configuraci�n
    GuardarIni ficIni, "General", sTmp, sUserPath
    GuardarIni ficIni, "General", "Usuario", sUsuario
    
    numBases = Combo1.ListCount
    GuardarIni ficIni, "General", "NumeroBases", CStr(numBases)
    'Guardar los nombres
    For i = 1 To numBases
        sTmp = "Base" & Format$(i, "00")
        sBase = Combo1.List(i - 1)
        GuardarIni ficIni, "General", sTmp, sBase
    Next
    
    'Asignar el nombre de la base a la variable global
    sBase = sUserBase
    gsNotas.Show
    'Descargar este form
    Unload Me
End Sub



Antes de ver el resto, hagamos un alto en el camino.
Entre otras cosas, porque en el c�digo del bot�n Aceptar hay tres rutinas que debemos revisar.
La primera es la funci�n ActualizarLista. �sta funci�n la vamos a declarar Global, ya que su uso nos ser� de utilidad en el Form principal o en otro, ya veremos.
As� pues, la incluiremos en el m�dulo global. Abre �ste m�dulo y a�ade la siguiente declaraci�n en la secci�n de las Declaraciones: (
fijate que lParam est� declarada com Any en lugar de Long)

'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
#Else
    Declare Function SendMessage Lib "User" _
        (ByVal hWnd As Integer, ByVal wMsg As Integer, _
         ByVal wParam As Integer, lParam As Any) As Long
#End If

Esto tambi�n lo debes incluir en el m�dulo global:

Public Function ActualizarLista(sTexto As String, cList As Control) As Long
    'Esta funci�n comprobar� si el texto indicado existe en la lista
    'Si no es as�, lo a�adir�
    'El valor devuelto, ser� la posici�n dentro de la lista � -1 si hay "fallos"
    '
    'Para buscar en el List/combo usaremos una llamada al API
    '(si ya hay una forma de hacerlo, �para que re-hacerla?)
    '
    Const CB_FINDSTRINGEXACT = &H158        'Mensaje para los combos
    Const LB_FINDSTRINGEXACT = &H1A2        'Mensaje para las Listas
    Dim L As Long
    
    If cList.ListCount = 0 Then
        'Seguro que no est�, as� que a�adirla
        L = -1
    Else
        'Si el control es un Combo
        If TypeOf cList Is ComboBox Then
            L = SendMessage(cList.hWnd, CB_FINDSTRINGEXACT, -1, ByVal sTexto)
        'Si el control es un list
        ElseIf TypeOf cList Is ListBox Then
            L = SendMessage(cList.hWnd, LB_FINDSTRINGEXACT, -1, ByVal sTexto)
        Else
            'no es un control List o Combo, salir
            ActualizarLista = -1
            Exit Function
        End If
    End If
    
    'Si no est�, a�adirla
    If L = -1 Then
        L = cList.ListCount
        cList.AddItem sTexto
    End If
    ActualizarLista = L
End Function

Bien, veamos que es lo que nos encontramos aqu�.
Esta funci�n har� lo siguiente:
Buscar� en la lista de items de un ListBox o ComboBox, la cadena especificada y si no existe, la a�adir�, devolviendo posteriormente la posici�n dentro de la lista.
Realmente cuando se a�ade un nuevo dato, devuelve la posici�n del �ltimo item.
Esto puede ser un problema si la lista est� ordenada.
Para solventarlo, despu�s de a�adir el dato, efect�a otra b�squeda llamando recursivamente a la funci�n!

    'Si no est�, a�adirla
    If L = -1 Then
        'L = cList.ListCount
        cList.AddItem sTexto
	L = ActualizarLista(sTexto, cList)
    End If

En el c�digo final del programa, he incluido �sta �ltima versi�n.
Fijate que hay dos llamadas a la funci�n SendMessage, una si es un ListBox y otra si es un ComboBox. Adem�s de efectuar una b�squeda "total", es decir que la cadena buscada debe existir completa, aunque el formato de may�sculas/min�sculas no se tenga en cuenta.
Para buscar s�lo una parte, desde el principio, usa las constantes:

Const LB_FINDSTRING = &H18F	'Para el listbox
Const CB_FINDSTRING = &H14C	'Para el combobox

La segunda rutina que te comentaba es: SplitPath y se encarga de "dividir" o seccionar una cadena en la ruta, el nombre del archivo y la extensi�n, estas dos �ltimas cosas las he puestos como opcionales, (he dejado el nombre en ingl�s, porque creo que se entender� perfectamente el cometido que tiene)
Veamos el c�digo, que debe estar en el m�dulo global:

Public Sub SplitPath(ByVal sTodo As String, sPath As String, Optional vNombre, Optional vExt)
    '----------------------------------------------------------------
    'Divide el nombre recibido en la ruta, nombre y extensi�n
    '(c)Guillermo Som, 1997                         ( 1/Mar/97)
    '
    'Esta rutina aceptar� los siguientes par�metros:
    'sTodo      Valor de entrada con la ruta completa
    'Devolver� la informaci�n en:
    'sPath      Ruta completa, incluida la unidad
    'vNombre    Nombre del archivo incluida la extensi�n
    'vExt       Extensi�n del archivo
    '
    'Los par�metros opcionales s�lo se usar�n si se han especificado
    '----------------------------------------------------------------
    Dim bNombre As Boolean      'Flag para saber si hay que devolver el nombre
    Dim i As Integer
    
    If Not IsMissing(vNombre) Then
        bNombre = True
        vNombre = sTodo
    End If
    
    If Not IsMissing(vExt) Then
        vExt = ""
        i = InStr(sTodo, ".")
        If i Then
            vExt = Mid$(sTodo, i + 1)
        End If
    End If
        
    sPath = ""
    'Asignar el path
    For i = Len(sTodo) To 1 Step -1
        If Mid$(sTodo, i, 1) = "\" Then
            sPath = Left$(sTodo, i - 1)
            'Si hay que devolver el nombre
            If bNombre Then
                vNombre = Mid$(sTodo, i + 1)
            End If
            Exit For
        End If
    Next
End Sub

Un poco de aclaraci�n: Esta rutina recibe una cadena con el nombre completo de la ruta y el archivo y devolver� la ruta y opcionalmente el nombre, (con la extensi�n incluida), y, (tambi�n opcionalmente), la extensi�n.

La tercera rutina es la que se encargar� de crear la base de datos, pero la vamos a dejar para otra ocasi�n, ya que merece m�s atenci�n. En principio, s�lo tienes que dejar la declaraci�n, para que puedas probar lo que estamos haciendo.

Private Sub CrearBase(sBase As String)
    'Crear la base de datos indicada
    '
    '===POR HACER===
    '
End Sub

Y para poder probarlo, debes especificar el form Entrada como punto de "entrada", valga la redundancia, del programa. Para ello, en el men� Tools, selecciona la opci�n Options... y en la leng�eta Project selecciona en Startup Form �se formulario.

Para terminar, vamos a ver el resto del c�digo del formulario de Entrada.
En primer lugar �que es lo que hay que hacer cuando un form se cierra?

'C�digo del Formulario Entrada
Private Sub Form_Unload(Cancel As Integer)
    'Liberar memoria
    Set frmEntrada = Nothing
End Sub

Ahora veamos el c�digo del bot�n Examinar...

Private Sub cmdExaminar_Click()
    'Abrir el control de di�logos comunes y "localizar"
    'los archivos con extensi�n MDB
    'Seleccionar el fichero en el que se empezar� la Busqueda
    
    On Local Error Resume Next
    
    CommonDialog1.DialogTitle = "Seleccionar Base de Datos"
    CommonDialog1.Filter = "Bases (*.mdb)|*.mdb|Todos los archivos (*.*)|*.*"
    CommonDialog1.FilterIndex = 1
    CommonDialog1.CancelError = True
    CommonDialog1.ShowOpen
    If Err Then
        Err = 0
    Else
        Combo1.Text = CommonDialog1.filename
    End If
End Sub

Y por �ltimo el bot�n Cancelar:

Private Sub cmdCancelar_Click()
    'Terminar el programa!!!
    Unload Me
    End
End Sub


Bueno, esto es todo por ahora. (
Si quieres experimentar, fijate que no se hace ninguna comprobaci�n de que la extensi�n sea correcta en el cmdAceptar)
Ma�ana m�s.


Pulsa aqu� si quieres bajar los listados de ejemplo y los archivos HTML (gsnotas.zip 21.4 KB)
(Este tama�o variar�, seg�n el n�mero de entregas; para saber el tama�o actual, deber�as ver la �ltima entrega)