Esta es la segunda parte de “Maximizando el reúso de código”. La parte uno  se enfocó en  asignar más de un manejador de eventos al mismo evento de un objeto o  compartir el mismo manejador de eventos para diferentes objetos. Ahora hablaremos de cómo podemos escribir automatizaciones en tiempo de diseño para ayudarnos a ahorrar tiempo a la hora de programar.

Si le encanta escribir, deténgase no continúe leyendo esto.

Algunas veces recibimos una base de datos de otra persona y nos damos cuenta que necesitamos hacer mucho trabajo para optimizarla. Para comenzar, supongamos que queremos agregar KeyNavigator -mencionando en  la parte uno -a 100 formularios continuos repartidos en la base de datos de Access. Recuerde que le mostramos como podíamos reducir los requerimientos de configuración en cada formulario con solo 4 líneas de código, pero 400 líneas de código siguen siendo mucho por escribir.

¿Para qué escribir cuando podemos hacer que VBA lo haga por nosotros?

Verifique antes de ejecutar el código que tenga la referencia de “Microsoft Visual Basic para Aplicaciones Extensible 5.3”. Solo la necesita mientras se ejecuta el código, puede removerla después.

Utilizando el objeto Module, podemos escribir un procedimiento desde cero en un módulo para optimizar el trabajo por nosotros. Es típico tener un módulo principal agregado a nuestro proyecto – quizás llamado “zzScrathPad” así que la lista lo organiza al final de manera ascendente. También preferimos hacer todos los procedimientos privados, porque la intensión no es usarlo en tiempo de ejecución. La única manera de ejecutarlo es desde el editor de VBA, el cual es el apropiado para nuestro propósito.

Como necesitamos agregar 4 líneas de código para todos los formularios continuos, necesitamos configurar un ciclo que los recorra todos. Para reducir los errores asociados con los múltiples formularios que están abierto (ej.. usted no puede abrir un formulario en modo diseño cuando ya está abierto como subformulario de otro formulario), cerraremos todo los objetos y trabajaremos solo con uno a la vez, además, es posible que no tengamos un módulo para cada formulario, tenemos que asegurarnos de hacer uno.

Private Sub StartAddKNInitCode()
Dim ao As Access.AccessObject

On Error GoTo ErrHandler

DoCmd.RunCommand acCmdCloseAll
If Forms.Count Then
    MsgBox "Cannot process; there are still open forms. Please close them."
    Exit Sub
End If

For Each ao In CurrentProject.AllForms DoCmd.OpenForm ao.Name, acDesign, , , , acHidden With Forms(ao.Name) If .DefaultView = 1 Then 'It's a continuous form If .HasModule = False Then .HasModule = True 'Add a module DoCmd.Save acForm, ao.Name End If AddKNInitCode .Module End If End With DoCmd.Close acForm, ao.Name Next ExitProc: On Error Resume Next Exit Sub ErrHandler: Select Case Err.Number Case Else MsgBox "Error " & Err.Number & " (" & Err.Description & ")" End Select Resume ExitProc Resume End Sub

Ahora tenemos el formulario correcto y su módulo adquirido, existen otras cosas que tenemos que tomar en cuenta. ¿Qué pasa si un formulario ya tiene un manejador de eventos creado? No queremos código duplicado ni con errores porque no compilará. Así que necesitamos examinar el módulo para determinar si hay un manejador de eventos y editarlo o agregar uno nuevo de una manera apropiada.

Private Sub AddKNInitCode(FormModule As Access.Module)
Dim l As Long 'Line Pointer
Dim i As Long 'Iterator
Dim b As Long 'Start point
Dim c As Long 'End point
Dim s As String 'Current Line Text
Dim bolHasIt As Boolean

Const Evented As String = "[Event Procedure]"
Const VariableLine As String = "Private kn As KeyNavigator"
Const InitLines As String = "Set kn = New KeyNavigator" & vbNewLine & "kn.Init Me"
Const DestLine As String = "Set kn = Nothing"

On Error GoTo ErrHandler
bolHasIt = False
b = 1
c = FormModule.CountOfDeclarationLines
For i = b To c
  s = FormModule.Lines(i, 1)
  Select Case s
    Case VariableLine
      bolHasIt = True
      Exit For
  End Select
Next
If Not bolHasIt Then
  FormModule.InsertLines c + 1, VariableLine
End If

bolHasIt = False
l = 0

On Error Resume Next
l = FormModule.ProcBodyLine("Form_Load", vbext_pk_Proc)
On Error GoTo ErrHandler
If l Then
  s = FormModule.Lines(l, FormModule.ProcCountLines("Form_Load", vbext_pk_Proc))
  If InStr(s, InitLines) = 0 Then
    If InStr(s, "On Error GoTo") = 0 Then
      FormModule.InsertLines l + 1, InitLines
    Else
      b = l
      c = l + FormModule.ProcCountLines("Form_Load", vbext_pk_Proc)
      For i = b To c
        s = FormModule.Lines(i, 1)
        If InStr(s, "On Error GoTo") Then
          FormModule.InsertLines i + 1, InitLines
          Exit For
        End If
      Next
    End If
  End If
Else
  FormModule.Parent.OnOpen = Evented
  FormModule.InsertText _
    "Private Sub Form_Load()" & vbNewLine & _
    InitLines & vbNewLine & _
    "End Sub" & vbNewLine
End If
bolHasIt = False
l = 0

On Error Resume Next
l = FormModule.ProcBodyLine("Form_Close", vbext_pk_Proc)
On Error GoTo ErrHandler
If l Then
  s = FormModule.Lines(l, FormModule.ProcCountLines("Form_Close", vbext_pk_Proc))
  If InStr(s, DestLine) = 0 Then
    If InStr(s, "On Error GoTo") = 0 Then
      FormModule.InsertLines l + 1, DestLine
    Else
      b = l
      c = FormModule.ProcCountLines("Form_Close", vbext_pk_Proc)
      For i = b To c
        s = FormModule.Lines(i, 1)
        If InStr(s, "On Error GoTo") Then
          FormModule.InsertLines i + 1, DestLine
          bolHasIt = True
          Exit For
        End If
      Next
      If bolHasIt = False Then
        FormModule.InsertLines l + 1, DestLine
      End If
    End If
  End If
Else
  FormModule.Parent.OnClose = Evented
  FormModule.InsertText _
    "Private Sub Form_Close()" & vbNewLine & _
    DestLine & vbNewLine & _
    "End Sub"
End If

DoCmd.Save acForm, FormModule.Parent.Name

ExitProc:
    On Error Resume Next
    Exit Sub
ErrHandler:
    Select Case Err.Number
  Case Else
      MsgBox "Error " & Err.Number & " (" & Err.Description & ") on Line: " & Erl
    End Select
    Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    Resume
End Sub

Ahora tenemos 4 líneas agregadas automáticamente en todos nuestros formularios. Como el código también verifica si existen esas 4 líneas, lo podemos ejecutar una y otras vez si agregamos más formularios continuos y solo le agrega la 4 líneas de código si el formulario no las tiene. Esto es muy útil cuando usted posee 100 formularios en un archivo de Access que no existen en otro.

Obviamente, usted tendrá que adaptar el código a sus necesidades. Crear un conjunto de rutinas para actualizar una base de datos vieja y adaptarla con sus nuevas librerías y objetos ahora es bien sencillo. ¡Feliz automatización!