jueves, 26 de febrero de 2015

Recorrer subformulario

Esta es una de las cosas, que estuve años haciéndolo manual, hasta que Patxi Sanz me enseñó a hacerlo, después con el paso del tiempo, me doy cuenta que existen más formas de hacerlo, así que les voy a mostrar varias de ellas, para este ejemplo conté con la colaboración de MexMan70. Veremos 7 formas diferentes que podemos llamar:

1.-Recordsetclone directo
2.-Recordsetclone con recordcount
3.-Recordsetclone con absoluteposition
4.-En la tabla con Recordset
5.-Consulta con Execute
6.-Consulta con DoCmd.RunSQL
7.-Desde el subformulario

Vamos a necesitar una tabla, le llamaremos Productos y constará de 4 campos id Autonumerico, Nombre (texto), Precio (número) e Importe (número), y agregamos algunos registros:


Productos
id Nombre Precio Importe
1 Tomate 3 6
2 Cebolla 4 8
3 Papa 5 10
4 Lechuga 6 12


Creamos un formulario en blanco, y  en vista diseño agregamos la tabla Productos y la dejamos caer dentro del formulario, nos pregunta que nombre le queremos dar y le decimos que Subproductos, agregamos un cuadro de texto y 7 botones, luego iremos cambiando los nombres, se ve más o menos así:




1.-Recordsetclone directo
Podemos decir que Recordsetclone es una copia de la consulta o tabla de la que se basa el formulario y se usa para navegar y realizar operaciones en los registros del formulario. Y si hacemos un bucle podemos recorrerlos, nosotros lo haremos con Do Loop para ir actualizando cada registro.
Ahora en vista diseño vamos a ponerle de nombre: Cantidad al cuadro de texto y al primer botón lo llamaremos RecordClone y en eventos al hacer click le damos a los 3 puntos y le decimos que generador de código y nos lleva a vba, y entre Private Sub RecordClone_Click() y End Sub ponemos:

With Me.SubProductos.Form.RecordsetClone
.MoveFirst
Do Until .EOF
    .Edit
    !Importe = !Precio * Me.cantidad
    .Update
    .MoveNext
    Loop    
End With

Podemos probar nuestro primer Botón, poniendo algún número en el campo cantidad y dándole al botón y debe verse parecido a esto:




2.-Recordsetclone con recordcount
Es una pequeña variante del anterior solo que ahora usaremos un For Next y contaremos los registros con RecordCount asi que en el Botón segundo le cambiamos el nombre a RecordCloneCount y de nuevo, nos vamos a eventos, al hacer click y generador de código y ponemos:
Private Sub RecordCloneCount_Click()
Dim rs As DAO.Recordset 
Dim i As Integer 
Set rs = Me.SubProductos.Form.RecordsetClone 
If Not rs.BOF Then 
rs.MoveFirst 
For i = 1 To rs.RecordCount 
    rs.Edit 
    rs!Importe = Me.cantidad * rs!Precio 
    rs.Update 
    rs.MoveNext 
Next i
End If
rs.Close
Set rs = Nothing 
End Sub

Probamos el nuevo botón.
3.-Recordsetclone con absoluteposition
Este es muy parecido al primero solo que cuando lleguemos al final de los registros, nos vamos a salir cuando AbsolutePosition sea igual al total de los registros. En el tercer botón le cambiamos nombre y le ponemos RecordCloneAbsolute, y nos vamos a eventos, al hacer click y generador de código y ponemos:
Private Sub RecordCloneAbsolute_Click()
With Me.SubProductos.Form.RecordsetClone
 .MoveFirst
   Do
    .Edit
    !Importe = !Precio * Me.cantidad
    .Update
     If .AbsolutePosition = .RecordCount - 1 Then Exit Do
     .MoveNext
   Loop
End With
End Sub
Probamos el nuevo botón.
4.-En la tabla con Recordset
Con un Recordset directo en la tabla, también puede ser bastante fácil, en el cuarto botón le cambiamos nombre y le ponemos Recordset, y nos vamos a eventos, al hacer click y generador de código y ponemos:
Private Sub Recordset_Click()
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("SELECT id, Nombre, Precio, Importe FROM Productos", dbOpenDynaset)
rs.MoveFirst
Do While Not rs.EOF
    rs.Edit 
    rs![Importe] = rs!Precio * Me.cantidad 
    rs.Update
    rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Me.Refresh
End Sub

Probamos el nuevo botón.
5.-Consulta con Execute
Las consultas son las formas más directas y quizás las más rápidas, podemos usar Execute y DoCmd.RunSQL  y usando variable o no, vamos a ver la primera, en el quinto botón le cambiamos nombre y le ponemos CtaExecute, y nos vamos a eventos, al hacer click y generador de código y ponemos:

Private Sub CtaExecute_Click()
Dim SQL As String
SQL = "UPDATE Productos SET Importe = Precio * '" & Me.cantidad & "'"
    CurrentDb.Execute SQL, dbFailOnError
Me.Refresh
End Sub

Probamos el nuevo botón.
6.-Consulta con DoCmd.RunSQL
Las consultas son las formas más directas y quizás las más rápidas, podemos usar Execute y DoCmd.RunSQL  y usando variable o no, vamos a ver la segunda y sin variable, en el sexto botón le cambiamos nombre y le ponemos CtaRunSQL, y nos vamos a eventos, al hacer click y generador de código y ponemos:
Private Sub CtaRunSQL_Click()
DoCmd.RunSQL "UPDATE Productos SET Importe = Precio * '" & Me.cantidad & "'"
Me.Refresh
End Sub

Probamos el nuevo botón.
7.-Desde el subformulario
Esta es una idea de Patxi en la que en cada registro del subformulario tenemos que crear el procedimiento que actualiza registro por registro y para poder usarlo en el formulario principal declaramos el procedimiento como Public en el subformulario. Entonces aquí primero tenemos que irnos al subformulario y en el control Importe, eventos, después de actualizar, generador de código y Primero cambiamos Private por Public y ponemos:

Public Sub Importe_AfterUpdate()
Me.Importe = Me.Precio * Me.Parent.cantidad
End Sub

Después en el séptimo botón le cambiamos nombre y le ponemos Subform, y nos vamos a eventos, al hacer click y generador de código y ponemos:

Private Sub Subform_Click()
Me.SubProductos.SetFocus
    With Me.SubProductos.Form
        .Precio.SetFocus
        DoCmd.GoToRecord , , acFirst
        Do While Not .NewRecord
            .Importe_AfterUpdate
            DoCmd.GoToRecord , , acNext
        Loop
    End With
End Sub

Y está listo para probarlo.



Puede bajar el archivo
https://www.dropbox.com/s/5fudwwgrsbrw5ry/Recorrosubfor.mdb?dl=0