** NORMAS DEL FORO **
Inicio del foro Inicio del foro > Access y VBA > Access y VBA
  Mensajes nuevos Mensajes nuevos RSS - Abrir un formulario en un registro determinado
  Preguntas frecuentes Preguntas frecuentes  Buscar en el foro   Eventos   Registro Registro  Iniciar sesion Iniciar sesion

Tema cerradoAbrir un formulario en un registro determinado

 Responder Responder Página  12>
Autor
Mensaje
Antonalo Ver desplegable
Asiduo
Asiduo
Avatar

Unido: 06/Noviembre/2009
Localización: España
Estado: Sin conexión
Puntos: 437
Enlace directo a este mensaje Tema: Abrir un formulario en un registro determinado
    Enviado: 08/Mayo/2015 a las 23:07
Esto ya para mi es sencillo gracias a lo mucho que he aprendido aquí. Sin embargo ahora me he encontrado un problema inesperado y tengo curiosidad por saber como lo resolveríais los grandes maestros que hay en este foro:

Desde el formulario AGENDA, en un determinado registro donde el campo IdPersona tiene un determinado valor, quiero abrir el formulario PERSONAS ,  En el registro de ese id. (el IdPersona es autonumérico en PERSONAS). Creo un botoncito y en el evento de hacer clic escribo: (Con el asistente que me crea el farragoso control de errores)

Private Sub CmdAbrirPersonas_Click()
On Error GoTo Err_CmdAbrirPersonas_Click

    Dim stDocName As String
    Dim stLinkCriteria As String
    
    stLinkCriteria = "IdPersona =" & Me.IdPersona
    stDocName = "PERSONAS"
    
   
    DoCmd.OpenForm stDocName, , , stLinkCriteria
  
Exit_CmdAbrirPersonas_Click:
    Exit Sub

Err_CmdAbrirPersonas_Click:
    MsgBox Err.Description
    Resume Exit_CmdAbrirPersonas_Click
    
End Sub


Y resulta que PERSONAS,  siempre se abre en el primer registro. Como creo que el código es correcto, investigo un poco y me acuerdo que PERSONAS tiene también un código al cargar:
Private Sub Form_Load()
    
     Me.Form.Filter = "EstadoActivoPersona = -1"
     Me.Form.FilterOn = True
    
End Sub

Esto hace que solo me aparezcan las personas que no he desactivado mediante un campo si/no

Llego por tanto a la conclusión de que el primer código solo se me va a ejecutar si PERSONAS  está ya abierto y por tanto modifico el primer código:

Private Sub CmdAbrirPersonas_Click()
On Error GoTo Err_CmdAbrirPersonas_Click

    Dim stDocName As String
    Dim stLinkCriteria As String
    
    stLinkCriteria = "IdPersona =" & Me.IdPersona
    stDocName = "PERSONAS"
    
    DoCmd.OpenForm stDocName
    DoCmd.OpenForm stDocName, , , stLinkCriteria
  
Exit_CmdAbrirPersonas_Click:
    Exit Sub

Err_CmdAbrirPersonas_Click:
    MsgBox Err.Description
    Resume Exit_CmdAbrirPersonas_Click
    
End Sub

Lo que pasa, es que aunque funciona, no creo que sea una solución elegante aunque eso sí, sencilla

¿hay alguna manera más correcta de hacer esto?







Arriba
MexMan70 Ver desplegable
Colaborador
Colaborador


Unido: 17/Julio/2007
Localización: DarkSide
Estado: Sin conexión
Puntos: 9235
Enlace directo a este mensaje Enviado: 09/Mayo/2015 a las 00:12
Usando OpenArgs en el Formulario a abrir y usar al momento de lanzar su apertura el parametro OpenArgs, huelga decir que solo deberás pasar la variable en la cual tienes la clave a buscar.

En el formulario PERSONAS al momento de cargar averiguas si se ha pasado un argumento, si se le ha pasado entonces se posiciona usando el apuntador (Bookmark).

Esta solucion ya ha salido en el foro, puedes usar el buscador y teclear Bookmark.
OneDrive: http://sdrv.ms/Vk6eJd
Arriba
VIMIPAS Ver desplegable
Colaborador
Colaborador
Avatar

Unido: 06/Enero/2006
Localización: ESPAÑA
Estado: Sin conexión
Puntos: 5360
Enlace directo a este mensaje Enviado: 09/Mayo/2015 a las 00:35
Hola buenas noches Antonalo.

Con el permiso de Roberto (saludos )...

Te propongo otra alternativa, así ya tienes alguna mas. Esta:

Option Compare Database
Option Explicit

Private Sub Comando4_Click()
On Error GoTo Err_Comando4_Click
'Este es el formulario "Pruebaclientes" que abrirá el subformulario
    Dim stDocName As String
    Dim stLinkCriteria As String

    stDocName = "subformulario"
    
    stLinkCriteria = "[NUMERO_ID]=" & Me![NUMERO_ID]

    DoCmd.OpenForm stDocName, , , stLinkCriteria

Exit_Comando4_Click:
    Exit Sub

Err_Comando4_Click:
    MsgBox Err.Description
    Resume Exit_Comando4_Click
    
End Sub


Y esto es lo que tengo en el subformulario:

Option Compare Database
Option Explicit

Private Sub Form_Load()
If CurrentProject.AllForms("PRUEBACLIENTES").IsLoaded Then
    'MsgBox "ABIERTO"... POR LO TANTO NO EJECUTO EL FILTRO DEL load()
Else
    'MsgBox "cerrado"... POR LO TANTO, ahora si, EJECUTO EL FILTRO DEL load()
    Me.Filter = "EstadoActivoPersona = -1"
    Me.FilterOn = True
End If
End Sub

Como habrás visto, es el mismo Load() que tienes tu, pero con la variante de que cuando va a ejecutarse el filtro, previamente comprueba si el otro formulario (el "Pruebaclientes") está abierto.


Si está abierto=No filtro nada
No está abierto=Si filtro los que estén con el -1

Cuanto mas sepas, mas podrás elegir.

Saludos


Editado por VIMIPAS - 09/Mayo/2015 a las 00:35
Gracias
Arriba
Antonalo Ver desplegable
Asiduo
Asiduo
Avatar

Unido: 06/Noviembre/2009
Localización: España
Estado: Sin conexión
Puntos: 437
Enlace directo a este mensaje Enviado: 11/Mayo/2015 a las 13:11
Respondo un poco tarde porque he estado estudiando Apenargs y BookMark aunque con este último no me aclaro mucho y no sé darle una aplicación

las dos respuestas me sirven para aclararme. La de MexMnme parece la más correcta aunque la segunda me da la idea de como aplicarlo.

El método de VIMIPAS lo entiendo sin más pero tiene el problema que el código del formulario PERSONAS no se va a ejecutar si AGENDA está abierto y eso no es lo que quiero. Lo que quiero es que no se ejecute solo cuando desde AGENDA doy la orden de abrir PERSONAS, porque si se ejecutara, me invalida la orden de buscar a la persona

Entonces he escrito:

En el formulario Agenda:

Private Sub CmdAbrirPersonas_Click()
   
DoCmd.Save

    Dim stDocName As String
    Dim stLinkCriteria As String
    
    stLinkCriteria = "IdPersona =" & Me.IdPersona
    stDocName = "PERSONAS"
    
    DoCmd.OpenForm stDocName, , , stLinkCriteria, , , "NoNulo"
    DoCmd.Close acForm, "AGENDA"
    
End Sub

Y en el formulario Personas:

Private Sub Form_Open(Cancel As Integer)
     If IsNull(Me.OpenArgs) Then
     Me.Form.Filter = "EstadoActivoPersona = -1"
     Me.Form.FilterOn = True
     End If
End Sub

Sin embargo, aunque funciona bien, hay algo que no me convence, supongo que cualquier valor de openArgs valdría con tal que no sea nulo, y desde luego estoy desaprovechando el Bookmark que no sé para que me sirve en este caso.

Arriba
E. Feijoo Ver desplegable
Moderador
Moderador


Unido: 16/Abril/2004
Localización: España
Estado: Sin conexión
Puntos: 19948
Enlace directo a este mensaje Enviado: 11/Mayo/2015 a las 14:08
Solo por aclarar conceptos:

OpenArgs ==> una variable que solo 'existe' (se crea) cuando se utiliza, si no se utilizase (el que 'llame' al objeto no la utiliza) su valor seria un NULL (valor inexistente).
.- No tiene mucho sentido esto : ...., , , stLinkCriteria, , , "NoNulo"

Sobre BOOMARK ==> es una variable que se crea en el momento en que se abre un formulario y cada vez que se abra, se le asigna un valor a cada registro (un simil de un ID), su 'vida util' es la misma que la del formulario.

Cuando se abre un formulario se hace una copia sincrónica de los registros actuales de la tabla u origen de datos, a cada registro se le asigna el mencionado BOOMARK que es lo que utiliza Access para relacionar el origen de datos (ese recordset copia conocido como RecordsetClone) con el registro activo.

Dado que el RecordsetClone es todo el conjunto de datos del formulario, en el y con DAO se pueden hacer búsquedas y localizar un determinado registro, para 'convertir' el registro localizado en el registro activo se utiliza (porque lo comparten) el igualar sus respectivos BOOKMARK.

Mas o menos es asi:
----------------
nota-. como 'ya existe' no hace falta declarar recordset ni cerrarlo, simplemente lo tomamos 'prestado' y ahorramos recursos.
----------------

__Se efectúa una localización en el RecordsetClone
Si el código corre en el propio formulario seria ==> 'Me.RecodsetClone.FindFirst "[NUMERO_ID]=" & Me![NUMERO_ID]

Si el formulario es otro, su ruta absoluta ==> Forms.[Nombre del formulario].RecodsetClone.FindFirst "[NUMERO_ID]=" & Me![NUMERO_ID]

Se verifica que existe consultando su propiedad NoMatch (si se esta absolutamente seguro de su existencia, se puede saltar la verificación) ==> IF [.....].NoMatch Then

En el caso de existir se igualan los BookMark (el del formulario y su RecordsetClone) para que se desplace el formulario afectado al registro deseado.


¿Qué diferencias hay entre los diversos métodos? ...
.- un filtro siempre limitara el numero de registros del formulario (solo mostrara los que cumplan el filtro)
.- una localización y el desplazamiento harán activo al deseado pero el resto de registros seguirán estando accesibles.
Arriba
mounir Ver desplegable
Colaborador
Colaborador


Unido: 09/Febrero/2009
Localización: Asturias-España
Estado: Sin conexión
Puntos: 5424
Enlace directo a este mensaje Enviado: 11/Mayo/2015 a las 14:27



¡¡¡¡¡Espectacular Maestro E. Feijoo!!!!!.
Un Saludo.
Arriba
Antonalo Ver desplegable
Asiduo
Asiduo
Avatar

Unido: 06/Noviembre/2009
Localización: España
Estado: Sin conexión
Puntos: 437
Enlace directo a este mensaje Enviado: 11/Mayo/2015 a las 16:32
Muchas gracias Feijoo, nunca fallas.

Efectivamente, eso de "NoNulo", no me gusta nada, porque tal como lo utilizo, podría ser también "MalditaSeaMiSuegra" en fin, "CualquierCosa", serviría igualmente.

Lo he cambiado un pelín para que tenga un poco sentido:

En AGENDA:

Private Sub CmdAbrirPersonas_Click()

    DoCmd.Save

    Dim stDocName As String
    Dim stLinkCriteria As String
    
    stLinkCriteria = "IdPersona =" & Me.IdPersona
    stDocName = "PERSONAS"
    
    DoCmd.OpenForm stDocName, , , stLinkCriteria, , , "PersonaDeAgenda"
    DoCmd.Close acForm, "AGENDA"
    
End Sub

Y en PERSONAS:


Private Sub Form_Open(Cancel As Integer)

     If Me.OpenArgs = "PersonaDeAgenda" Then
     Exit Sub
     
Else
     Me.Form.Filter = "EstadoActivoPersona = -1"
     Me.Form.FilterOn = True
     End If
End Sub

No cambia mucho pero tiene más sentido. Tengo que tener en cuenta que desde otros formularios también puedo utilizar DoCmdOpenForm y de esa manera puedo diferenciar en el OpenArgs cuando la orden viene de uno u otro.

En Relación BOOKMARK, Me parece muy interesante el hecho de no filtrar sino simplemente desplazarse al registro que nos interesa. Pero eso me supone que ahora tengo que manejar nuevos conceptos para mí como:

RecordsetClone
FindFirst
NoMatch

Así que en cuanto digiera la información que Feijoo me ha dado, os pegaré el código correspondiente.



Arriba
VIMIPAS Ver desplegable
Colaborador
Colaborador
Avatar

Unido: 06/Enero/2006
Localización: ESPAÑA
Estado: Sin conexión
Puntos: 5360
Enlace directo a este mensaje Enviado: 11/Mayo/2015 a las 22:22
Hola buenas noches.

Publicado originalmente por Antonalo Antonalo escribió:

El método de VIMIPAS lo entiendo sin más pero tiene el problema que el código del formulario PERSONAS no se va a ejecutar si AGENDA está abierto y eso no es lo que quiero.


A lo mejor no me termino yo de entender, pero cuando desde el formulario AGENDA mandas a abrir el formulario PERSONAS, justo en ese momento se está cargando el evento Load() del formulario PERSONAS, y a continuación tu cierras el formulario AGENDA.

Esta es mi pregunta clara: Cuándo desde Agenda se abre Personas (justo en ese momento) ¿está el formulario AGENDA abierto o cerrado?.

Otra cosa que sucede a continuación es si "después" se cierra el propio formulario AGENDA.

¿Se ha comprobado si funciona tal cual digo o no se ha llegado a comprobar y/o tal vez se está dando por supuesto algo que no se ha probado?.

Antonalo, ¿serías tan amable de indicarnos si has hecho la prueba que indico.?.

Saludos
Gracias
Arriba
Antonalo Ver desplegable
Asiduo
Asiduo
Avatar

Unido: 06/Noviembre/2009
Localización: España
Estado: Sin conexión
Puntos: 437
Enlace directo a este mensaje Enviado: 11/Mayo/2015 a las 23:07
VIMIPAS, tu código funciona perfectamente, En lo último que he escrito,  puedes ver como primero
se ejecuta  DoCmd.OpenForm stDocName, , , stLinkCriteria, , , "PersonaDeAgenda". 

y luego

    DoCmd.Close acForm, "AGENDA"

Mi idea es que despues de abrirse PERSONAS en el registro elegido, se cierre AGENDA, ya que creo que es mejor cerrar los formularios, asi cuando los llamamos salen ya actualizados.

Tu código funciona bien, porque se ejecuta mientras AGENDA está abierto y entonces no se ejecuta el filtro de activos en el evento al abrir, del formulario personas.

El problema que le veo es que si AGENDA está abierto, siempre que yo llame a PERSONAS, (por ejemplo pinchando directamente en el formulario para que se abra) no se me va a ejecutar el filtro de activos, y el filtro tiene que ejecutarse independientemente si AGENDA está abierto o cerrado. El único momento en que no quiero que se me ejecute el filtro de activos es cuando desde AGENDA le doy la orden mediante el DoCmd.Openform, porque al ejecutarse el filtro de activos, me anula el filtro de la persona seleccionada en AGENDA, y el formulario se abre siempre en el primer registro.

Sin embargo, tu idea de crear una condición en el formulario personas, en el evento de al abrir, la he aprovechado mediante el openArgs que se crea en AGENDA. , y que no se va a crear si por cualquier otra razón quiero abrir el formulario personas (aunque AGENDA esté abierto)

Aun así, aunque me funciona bien, yo quiero aprender y aprovecharme de lo mucho que me podéis enseñar y creo que la mejor manera de agradeceros vuestro esfuerzo es con el mío, por tanto voy a estudiar la manera de aplicar el Bookmark con las enseñanzas de Feijoo, y lo que me dijo Mexman al principio. Quiero conseguir ir simplemente al registro de Personas deseado, sin necesidad de filtrar esa persona.




Editado por Antonalo - 11/Mayo/2015 a las 23:10
Arriba
Antonalo Ver desplegable
Asiduo
Asiduo
Avatar

Unido: 06/Noviembre/2009
Localización: España
Estado: Sin conexión
Puntos: 437
Enlace directo a este mensaje Enviado: 11/Mayo/2015 a las 23:12
Publicado originalmente por Antonalo Antonalo escribió:

VIMIPAS, tu código funciona perfectamente, En lo último que he escrito,  puedes ver como primero
se ejecuta  DoCmd.OpenForm stDocName, , , stLinkCriteria, , , "PersonaDeAgenda". 

y luego

    DoCmd.Close acForm, "AGENDA"

por tanto, la respuesta a tu pregunta es que Agenda está abierto cuando se abre Personas, y después se cierra.

Mi idea es que despues de abrirse PERSONAS en el registro elegido, se cierre AGENDA, ya que creo que es mejor cerrar los formularios, asi cuando los llamamos salen ya actualizados.

Tu código funciona bien, porque se ejecuta mientras AGENDA está abierto y entonces no se ejecuta el filtro de activos en el evento al abrir, del formulario personas.

El problema que le veo es que si AGENDA está abierto, siempre que yo llame a PERSONAS, (por ejemplo pinchando directamente en el formulario para que se abra) no se me va a ejecutar el filtro de activos, y el filtro tiene que ejecutarse independientemente si AGENDA está abierto o cerrado. El único momento en que no quiero que se me ejecute el filtro de activos es cuando desde AGENDA le doy la orden mediante el DoCmd.Openform, porque al ejecutarse el filtro de activos, me anula el filtro de la persona seleccionada en AGENDA, y el formulario se abre siempre en el primer registro.

Sin embargo, tu idea de crear una condición en el formulario personas, en el evento de al abrir, la he aprovechado mediante el openArgs que se crea en AGENDA. , y que no se va a crear si por cualquier otra razón quiero abrir el formulario personas (aunque AGENDA esté abierto)

Aun así, aunque me funciona bien, yo quiero aprender y aprovecharme de lo mucho que me podéis enseñar y creo que la mejor manera de agradeceros vuestro esfuerzo es con el mío, por tanto voy a estudiar la manera de aplicar el Bookmark con las enseñanzas de Feijoo, y lo que me dijo Mexman al principio. Quiero conseguir ir simplemente al registro de Personas deseado, sin necesidad de filtrar esa persona.


Arriba
VIMIPAS Ver desplegable
Colaborador
Colaborador
Avatar

Unido: 06/Enero/2006
Localización: ESPAÑA
Estado: Sin conexión
Puntos: 5360
Enlace directo a este mensaje Enviado: 11/Mayo/2015 a las 23:42
Hola de nuevo.

Tal vez haya aparecido yo para enseñar algo que en resumen se puede hacer de otra forma.

Me decanto, tras lo que indicas sobre lo que yo pongo, que utilices única y exclusivamente por lo que te están indicando Roberto y Emilio sobre OpenArgs y Bookmark.

De otro modo, al final mezclarás churras con meninas y no te servirá para nada de lo que te he puesto.

Ya tienes mi idea, Roberto y Enrique, adelante. Y disculpen por mi intromisión.

Saludos
Gracias
Arriba
MexMan70 Ver desplegable
Colaborador
Colaborador


Unido: 17/Julio/2007
Localización: DarkSide
Estado: Sin conexión
Puntos: 9235
Enlace directo a este mensaje Enviado: 12/Mayo/2015 a las 00:13
Nada que disculpar Vicente, al contrario, todo aporte creo que es bienvenido. Yo he sugerido en resumen un metodo el cual Enrique lo ha explicado estupendamente.

Respecto al código, no he puesto nada pues ya han salido hilos anteriormente donde se ha dado solución. De ahí que solicite que usara el buscador del foro para localizar esos temas y los mirara.

Saludos !
OneDrive: http://sdrv.ms/Vk6eJd
Arriba
Antonalo Ver desplegable
Asiduo
Asiduo
Avatar

Unido: 06/Noviembre/2009
Localización: España
Estado: Sin conexión
Puntos: 437
Enlace directo a este mensaje Enviado: 12/Mayo/2015 a las 00:34
VIMIPAAAS de eso nada, creeme que ha sido absolutamente necesaria la idea que me has aportado
para comprender como lo podía aplicar al openargs, muchisimas gracias, de verdad.

Bueno chicos, creo que lo he conseguido:

En el formulario AGENDA:

Private Sub CmdAbrirPersonas_Click()
 DoCmd.Save
 Dim stDocName As String
 stDocName = "PERSONAS"
    
    DoCmd.OpenForm stDocName, , , , , , Me.IdPersona 
    DoCmd.Close acForm, "AGENDA"
    
End Sub

Ya con esto, le voy a pasar en el Openargs, el Id de persona. En agenda solo pueden ir Idpersonas que YA EXISTEN en personas, luego no tengo que verificar el Match o NoMatch


Ahora, en el formulario PERSONAS:

Private Sub Form_Open(Cancel As Integer)
    If Not IsNull(Me.OpenArgs) Then
     
     Dim rst As Recordset
     Set rst = Me.RecordsetClone
    
      rst.FindFirst "IdPersona =" & Me.OpenArgs
     Me.Bookmark = rst.Bookmark
     
     rst.Close
    
     Else
     Me.Form.Filter = "EstadoActivoPersona = -1"
     Me.Form.FilterOn = True
    
     End If
End Sub


¿Que te parece Feijoo? Creo que he hecho los deberes ¿no?  me funciona perfectamente, Y a partir de ELse, también va bien, es decir, que si abro Personas independientemente, openargs es nulo y por tanto me filtra los activos.

Como siempre, muchas gracias A TODOS.  


Arriba
E. Feijoo Ver desplegable
Moderador
Moderador


Unido: 16/Abril/2004
Localización: España
Estado: Sin conexión
Puntos: 19948
Enlace directo a este mensaje Enviado: 12/Mayo/2015 a las 00:55
Si entiendes lo que has hecho y te funciona, felicidades, cuando desees mejorarlo (en aplicaciones sencillas no se aprecia gran diferencia), toma en consideración lo de evitar la creación de una copia de lo que ya tienes (el RecordsetClone) o puedes afianzar lo que has hecho iterando tres (o mas) veces la copia, algo como:
--(tomando tus datos)--

Dim rst As Recordset, rst1 As Recordset, rst2 As Recordset, rst3 As Recordset

Set rst = Me.RecordsetClone
Set rst1 = rst
Set rst2 = rst1
Set rst3 = rst2

rst3.FindFirst "IdPersona =" & Me.OpenArgs
... etc ...
rst1.Close
rst2.Close
rst3.Close



Hay una alternativa mas económica (en recursos):
Me.RecordsetClone.FindFirst "IdPersona =" & Me.OpenArgs
Me.Bookmark = Me.RecordsetClone.Bookmark

Y si aburre el largo nombre, se le puede aplicar por defecto:
With Me.RecordsetClone
.FindFirst "IdPersona =" & Me.OpenArgs
Me.Bookmark = .Bookmark
End With


Nota:
(esto no se aplica al RecordsetClone, no lo hemos abierto nosotros, solo lo utilizamos que para eso esta disponible)

En una programación ortodoxa y en aras de liberar los recursos que consumen los recordset, no solo han de cerrarse, también se ha de limpiar el espacio utilizado, esto es:

Tras cada RST.Close un ==> Set RST = Nothing
Arriba
Antonalo Ver desplegable
Asiduo
Asiduo
Avatar

Unido: 06/Noviembre/2009
Localización: España
Estado: Sin conexión
Puntos: 437
Enlace directo a este mensaje Enviado: 12/Mayo/2015 a las 09:58
Bien, modifico entonces el código de PERSONAS:

Private Sub Form_Open(Cancel As Integer)
    If Not IsNull(Me.OpenArgs) Then
    
        Me.RecordsetClone.FindFirst "IdPersona =" & Me.OpenArgs
        Me.Bookmark = Me.RecordsetClone.Bookmark
       
      Else
      
        Me.Form.Filter = "EstadoActivoPersona = -1"
        Me.Form.FilterOn = True
      End If
End Sub


Y ya puestos, si se me permite una última pregunta de este tema..
¿Porqué hay que clonar el Recorset?

¿no bastaría con:
Me.Recordset.FindFirst "IdPersona =" & Me.OpenArgs     ?
Arriba
 Responder Responder Página  12>
  Compartir tema   

Ir al foro Permisos de foro Ver desplegable