Ritorrno al record selezionato in precedenza

di il
18 risposte

Ritorrno al record selezionato in precedenza

Buongiorno a tutti.
Ho un database per la gestione di un ambulatorio veterinario.
Ho una maschera per l'immissione di dati contenente due sottomaschere tra loro collegate.
- La main form (frmNuovaPrestazione) si basa sulla tabella tabPrestazioni (IDPrestazione PK, Data e vari altri campi)
- La prima subform (subfrmPazientiFrmNuovaPrestazione) sulla tabella tabIntestazioniPrestazioni (IDIntestazionePrestazione PK, IDPrestazione, IDPaziente)
- La seconda subform (subfrmDettaglioPrestazioni) sulla tabella tabDettagliPrestazioni (IDDettagliPrestazione PK, IDIntestazionePrestazione, IDPrestazione, IDProdotto, Descrizione ecc).

Le tabelle sono in relazione uno a molti a cascata.
Una prestazione ha molte IntestazioniPrestazioni.
Una IntestazionePrestazione ha molti DettagliPrestazioni.

Questo schema si è reso necessario dalle esigenze particolari dell'ambito per il quale è pensato.
In sostanza: un cliente (tabPrestazione), porta più animali (tabIntestazioniPrestazioni) ognuno dei quali riceve più prestazioni (tabDettagliPrestazioni).
Il tutto deve essere visualizzato in un'unica maschera di immissione che vi mostro qui:



Selezionando il paziente dalla sottomaschera centrale, si possono aggiungere le prestazioni relative a quel paziente (sottomaschera in basso). Nell'esempio sopra si stanno aggiungendo le prestazioni che riguardano il cane Fufi (evidenziato in blu).

Tutto funziona, ho solo un problema che non riesco a gestire.
Dopo aver immesso la nuova prestazione, in seguito al requery necessario per far comparire le nuove prestazioni nella sottomaschera, la maschera centrale (quella per la selezione del paziente) perde il focus. Il risultato è che il focus viene assegnato al primo paziente della lista (in questo caso il cane Ginger).

Ho provato a rimediare in vari modi, cercando di forzare il focus sul record corretto.
Ad esempio immettendo questo codice alla fine della procedura di immissione del nuovo record. In questo modo:
With Me.subfrmPazientiFrmNuovaPrestazione
                .SetFocus
                .Form.RecordsetClone.FindFirst "[IDIntestazionePrestazione]=" & Me.txtLink
                .Form.Bookmark = .Form.RecordsetClone.Bookmark
            End With
Ottengo però errore
Errore di run-time 3420. Oggetto non valido o non impostato
Non riesco a capire perché.

Dove sbaglio?

Grazie come sempre per l'aiuto

18 Risposte

  • Re: Ritorrno al record selezionato in precedenza

    RaoulDuke ha scritto:


    With Me.subfrmPazientiFrmNuovaPrestazione
                    .SetFocus
                    .Form.RecordsetClone.FindFirst "[IDIntestazionePrestazione]=" & Me.txtLink
                    .Form.Bookmark = .Form.RecordsetClone.Bookmark
                End With
    Ottengo però errore
    Errore di run-time 3420. Oggetto non valido o non impostato
    Però non indichi quale riga è evidenziata nell'errore.
    Dove scrivi quel codice (evento e modulo) e come fai il requery?
    Fai attenzione al fatto che dopo un Requery la maschera potrebbe diventare "non associata" e per riassociarla bisogna aggiungere un
    Me.RecordSource = Me.RecordSource
    Se questo non risolve, segui il ragionamento che scrivo qui sotto.
    In generale, facciamo che il codice è nella sottomaschera "subfrmDettaglioPrestazioni"
    - con il suo RecordsetClone ti posizioni sull'ultimo record inserito
    Me.RecorsetClone.Bookmark = Me.RecordsetClone.LastModified
    - da quello prelevi il l'IDPaziente (immagino che sia numerico, se è testo adatta la variabile)
    lngIDPaziente = Me.RecordsetClone![IDPaziente].Value
    - vai cercare quell'IDPaziente della maschera "subfrmPazientiFrmNuovaPrestazione" (che è tra l'altro Parent di subfrmDettaglioPrestazioni)
    (se IDPaziente è testo devi anche racchiuderlo tra apici singoli)
    Me.Parent.RecordsetClone.FindFirst "[IDPaziente] = " & lngIDPaziente
    - sincronizzi i bookmark di quella maschera
    Me.Parent.Recordset.Bookmark = Me.Parent.RecordsetClone.Bookmark
    Occhio che è tutto codice scritto al volo, non l'ho provato, forse ci sono anche errori di digitazione.
    In questa fase usa variabili in abbondanza a titolo di debug, per vedere dove sono i problemi (tipo l'uso che ho fatto io di lngIDPaziente).
    Se il codice del requery non si trova nella maschera subfrmDettaglioPrestazioni bisogna cambiare, ovviamente.
    L'importante è che si capisca il concetto (quindi non la parte scritta qui come codice ma "i passaggi")
  • Re: Ritorrno al record selezionato in precedenza

    Ciao Phil e grazie per la risposta.
    Nel frattempo ho fatto un po' di debug ed ho scoperto una cosa interessante. A causare la perdita di focus sul record attuale della subform centrale (per la scelta del paziente) non è il requery dell'altra sottomaschera, bensì il codice che ho associato all'evento "su modifica" di una combobox che serve alla scelta del prodotto da immettere.

    Come ho già spiegato in altri post, vorrei che l'utente possa digitare una stringa nella combobox e trovare tutti i prodotti che iniziano con quella stringa ma anche quelli che la contengono.

    A tale scopo ho scritto questo codice:
    Private Sub cboIDProdotto1_Change()
    Dim strR As String
    Dim strSQL As String
    
    'Me!cboIDProdotto1.SetFocusstrR = Me!cboIDProdotto1.Text
    If Not IsNull(Me!cboIDProdotto1.Text) Then
        strSQL = "SELECT tabProdotti.IDProdotto, tabProdotti.Descrizione" & _
                " FROM tabProdotti" & _
                " WHERE (tabProdotti.Descrizione LIKE " & Chr$(34) & "*" & strR & "*" & Chr$(34) & ")" & _
                " ORDER BY tabProdotti.Descrizione; "
        Me!cboIDProdotto1.RowSource = strSQL
        Me.cboIDProdotto1.Dropdown
    End If
    End Sub
    Se rinuncio a questo codice, il problema non si presenta più. Avevo già in mente di provare a trovare sistemi alternativi a questo metodo, li proverò e vedrò se la cosa risolve anche la perdita del focus.
    Detto questo, mi piacerebbe comunque capire cosa non funziona.

    Per rispondere alle tue domande.

    Il codice che ho linkato prima parte al click del pulsante Inserisci (controllo posto nella maschera principale frmNuovaPrestazione). L'utente sceglie il prodotto dal menu della combobox e poi clicca il pulsante che fa partire l'inserimento del nuovo record nella maschera.
    Il tuo procedimento lo capisco, ed è esattamente quello che tento di fare.
    Ho adattato il mio codice originale seguendo i tuo consigli.

    Ecco la situazione attuale:
    Private Sub cmdInserisci1_Click()
        'Verifico compilazione Prodotto e Quantità
        If IsNull(Me.cboQuantita1) Then
            MsgBox "Inserire una quantità!", vbExclamation + vbOKOnly, "Quantità mancante"
        Else
            If IsNull(Me.cboIDProdotto1) Then
                MsgBox "Scelgiere un prodotto dalla lista!", vbExclamation + vbOKOnly, "Prodotto mancante"
            Else
        
                'Ricavo Descrizione Prodotto
                Dim DescrizioneProdotto As String
                    DescrizioneProdotto = DLookup("Descrizione", "tabProdotti", "IDProdotto = " & Me.cboIDProdotto1)
                     
                'Ricavo IDListino
                Dim Listino As Integer
                    Listino = DLookup("IDListino", "tabClienti", "IDCliente =" & Me.cboIDCliente)
                 
                'Ricavo Prezzo Unitario
                Dim Prezzo As Double
                    Prezzo = retrieveIdPrezzoUnitario(Me.cboIDProdotto1, Listino, Me.Data)
                
                'Ricavo IDTipoIVA
                Dim TipoIVA As Integer
                    TipoIVA = DLookup("IDTipoIva", "tabProdotti", "IDProdotto =" & Me.cboIDProdotto1)
                     
                'Ricavo SubTotale
                Dim SubToto As Double
                    'Casi particolari
                    If Me.cboIDProdotto1 = 226 Or Me.cboIDProdotto1 = 235 Or Me.cboIDProdotto1 = 236 Or Me.cboIDProdotto1 = 239 Or Me.cboIDProdotto1 = 240 Then
                        SubToto = Round(Prezzo * Me.cboQuantita1 + 11, 1)
                    Else
                        SubToto = Round(Prezzo * Me.cboQuantita1, 1)
                    End If
                  
                'Inizio inserimento nuovo record          
                Dim wrk As DAO.Workspace
                Dim dbs As DAO.Database
                Dim rst As DAO.Recordset
                Dim Prestazione As Long
                
                Set wrk = DBEngine.Workspaces(0)
                Set dbs = CurrentDb
                Set rst = dbs.OpenRecordset("tabDettagliPrestazioni")
                
            
                    'Passo il focus sulla subformDettaglioPrestazioni per forzare l'immissione del record nella tabPrestazioni (la tabella della main form)
                    Me.SubForm1.SetFocus
                     
                    'Creo il nuovo record in Tabella Dettagli Prestazioni
                    rst.AddNew
                    rst![PrezzoUnitarioDef] = Prezzo
                    rst![IDIntestazionePrestazione] = Forms!frmNuovaPrestazione!subfrmPazientiFrmNuovaPrestazione.Form.IDIntestazionePrestazione
                    rst![IDProdotto] = Me.cboIDProdotto1
                    rst![Quantita] = Me.cboQuantita1
                    rst![Descrizione] = DescrizioneProdotto
                    rst![SubTotale] = SubToto
                    rst![IDTipoIva] = TipoIVA
                    rst![IDPrestazione] = Me.IDPrestazione
                    rst.Update
                    
               
    
                    'Mi sposto sull'ultimo record
                    Me.SubForm1.Form.Requery
                    DoCmd.GoToRecord , , acLast
    
                    'Pulisco le combobox per la scelta Prodotto
                    Me.cboIDProdotto1 = ""
                    Me.cboIDProdotto1.RowSource = "SELECT tabProdotti.IDProdotto, tabProdotti.Descrizione FROM tabProdotti ORDER BY tabProdotti.Descrizione;"
                    Me.cboQuantita1 = ""
                    
                    
                    rst.Close
                    dbs.Close
                    wrk.Close
                
                Set rst = Nothing
                Set dbs = Nothing
                Set wrk = Nothing
                
                'Qui vorrei riposizionarmi sul record corretto della subfrmPazientiFrmNuovaPrestazione
                Dim longIDIntestazione As Long
                    
                    Me!SubForm1.Form.RecordsetClone.Bookmark = Me!SubForm1.Form.RecordsetClone.LastModified
                    longIDIntestazione = Me!SubForm1.Form.RecordsetClone![IDIntestazionePrestazione].Value
                    Me!subfrmPazientiFrmNuovaPrestazione.Form.RecordsetClone.FindFirst "[IDIntestazionePrestazione] =" & longIDIntestazione
                    Me!subfrmPazientiFrmNuovaPrestazione.Form.Recordset.Bookmark = 	Me!subfrmPazientiFrmNuovaPrestazione.Form.RecordsetClone.Bookmark
            End If
        End If
    Exit Sub
    End Sub
    Continuo comunque ad ottenere lo stesso errore, la riga evidenziata è la prima riguardante il tentativo di riposizionamento, cioè
    Me!SubForm1.Form.RecordsetClone.Bookmark = Me!SubForm1.Form.RecordsetClone.LastModified
  • Re: Ritorrno al record selezionato in precedenza

    RaoulDuke ha scritto:


    Continuo comunque ad ottenere lo stesso errore, la riga evidenziata è la prima riguardante il tentativo di riposizionamento, cioè
    Me!SubForm1.Form.RecordsetClone.Bookmark = Me!SubForm1.Form.RecordsetClone.LastModified
    Il resto non l'ho guardato.
    Prova a togliere .Form
    Me!SubForm1.RecordsetClone.Bookmark = Me!SubForm1.RecordsetClone.LastModified
  • Re: Ritorrno al record selezionato in precedenza

    Già provato, stesso errore
  • Re: Ritorrno al record selezionato in precedenza

    Philcattivocarattere ha scritto:


    RaoulDuke ha scritto:


    Continuo comunque ad ottenere lo stesso errore, la riga evidenziata è la prima riguardante il tentativo di riposizionamento, cioè
    Me!SubForm1.Form.RecordsetClone.Bookmark = Me!SubForm1.Form.RecordsetClone.LastModified
    Il resto non l'ho guardato.
    Prova a togliere .Form
    Me!SubForm1.RecordsetClone.Bookmark = Me!SubForm1.RecordsetClone.LastModified
    Credo che tu debba togliere il primo recordsetclone ... :
    
    Me!SubForm1.Bookmark = Me!SubForm1.RecordsetClone.LastModified
    
    Guarda se può andarti bene una funzione (da aggiungere in un modulo) simile :
    
    Public Function GotoRecord_Form(FM_Form As Form, sFindRec As String) As Boolean
    FM_Form.RecordsetClone.FindFirst sFindRec
    If Not FM_Form.RecordsetClone.NoMatch Then
        FM_Form.Bookmark = FM_Form.RecordsetClone.Bookmark
        GotoRecord_Form = True
    End If
    End Function
    
    PS - Nella funzione manca la gestione degli errori ...
  • Re: Ritorrno al record selezionato in precedenza

    Ciao Max e grazie per la risposta.
    Idem come sopra: anche modificando in
    Me!SubForm1.Bookmark = Me!SubForm1.RecordsetClone.LastModified
    ottengo lo stesso errore.

    A questo punto eliminerò il codice della combobox e gestirò la ricerca del prodotto in altro modo, come peraltro consigliavi nell'altro post.
  • Re: Ritorrno al record selezionato in precedenza

    Ho provato a modificare la modalità di scelta del prodotto.
    Ho provato a sostituire la combobox con una textbox in cui l'utente digita la stringa da ricercare. Un pulsante popola la listbox e la rende visibile. Al click del record selezionato, la listbox sparisce e la textbox viene rimpostata a Null.

    Anche in questo caso soffro dello stesso problema: la subform che elenca i pazienti torna a posizionarsi sul primo paziente. Questo significa che devo assolutamente provare a risolvere l'errore. La perdita del focus sul record corretto avviene quando effettuo il requery della listbox. Subito dopo ho la perdita del focus..
    Ho provato anche in questo caso a forzare il focus sul record che era precedentemente selezionato. Così:
    Private Sub cmdCerca_Click()
        Dim lngIDIntestazione As Long
        lngIDIntestazione = Me.txtLink  'txtLink è un controllo testo della maschera principale che identifica il record attualmente selezionato
        
        Me.lstProdotti.Requery
        Me.lstProdotti.Visible = True
        
        With Me.subfrmPazientiFrmNuovaPrestazione
                    .SetFocus
                    .Form.RecordsetClone.FindFirst "[IDIntestazionePrestazione]=" & lngIDIntestazione
                    .Form.Bookmark = .Form.RecordsetClone.Bookmark
        End With
    End Sub
    
    Devo dire che a volte il codice funziona. Riesco ad ottenere l'effetto voluto.
    Ma poi ad un certo punto torna a non funzionare e riottengo lo stesso errore:
    Errore di run-time 3420. Oggetto non valido o non impostato
    sulla riga
    .Form.RecordsetClone.FindFirst "[IDIntestazionePrestazione]=" & lngIDIntestazione
    Davvero non riesco a capire cosa scateni l'errore.
  • Re: Ritorrno al record selezionato in precedenza

    Aggiungo a quanto già detto che il metodo funziona unicamente la prima volta che si apre la maschera principale.
    Se provo a passare ad un nuovo record vuoto ed a ripetere la procedura, ottengo l'errore.

    Nessuna idea?
  • Re: Ritorrno al record selezionato in precedenza

    Sarebbe necessario avere una copia del file, privo eventualmente di dati sensibili, per provare direttamente la situzione e verificare che cosa accade tramite il debug altrimenti credo che sia dura scoprire il motivo del comportamento citato.
  • Re: Ritorrno al record selezionato in precedenza

    RaoulDuke ha scritto:


    Aggiungo a quanto già detto che il metodo funziona unicamente la prima volta che si apre la maschera principale.
    Se provo a passare ad un nuovo record vuoto ed a ripetere la procedura, ottengo l'errore.

    Nessuna idea?
    Scusa ma non ho ben chiaro quale sia la PK della SubForm.
    Mi chiedo però perchè se fai un Requery di una ListBox sia da riposizionare una SubForm...?
    Nella sostanza, se ho ben capito, aggiungi un NuovoRecord all'Origine della SubForm...?
    Perchè riassegni il ROWSOURCE alla Combo...? (E' evidente che il ROWSOURCE sia statico, quindi perchè riassegnarlo...?)
    Perchè lo fai aprendo un Recordset separato quando hai già il RS della SubForm...?
    Usando opportunamente il RECORDSETCLONE di SubForm, basterebbe
    
    Dim rs As DAO.Recordset
    With Me!nomeSubform.Form.Recordsetclone
       .Addnew
       ......
       ......
       .Update
       .Move 0, .LastModified
       Me!nomeSubform.Form.Bookmark=.Bookmark
    End With
    Secondo me hai fatto un mix di idee confusionarie...
  • Re: Ritorrno al record selezionato in precedenza

    Intanto, come gentilmente richiesto da Stifone, vi allego una versione stringata del database con l'errore in questione.

    https://drive.google.com/file/d/1R0emIejSLw3M89N2jliKsevmZB0QxIf3/view?usp=sharing

    Per fare chiarezza, anche alla luce dell'intervento di Alex:

    La subform che presenta il problema della perdita del focus è la subfrmPazientiFrmNuovaPrestazione, che ha come origine dati la tabIntestazioniPrestazioni, con PK [IDIntestazionePrestazione]. È una subform che elenca i pazienti a cui vengono poi assegnate le prestazioni erogate.

    Al momento dell'immissione di un record alla tabella su cui si basa la subform, riesco senza problemi a spostarmi sul record desiderato (cioé l'ultimo inserito) a livello di maschera.
    Il focus viene poi perduto quando faccio un requery sulla listbox (o su un qualsiasi controllo della maschera principale). È una listbox che serve a selezionare il prodotto/prestazione da assegnare al paziente selezionato. Prima ho usato una combobox, che presentava lo stesso errore. Ho provato a passare alla listbox, ma l'errore permane.
    Riassegnare il RowSource alla combobox serviva per avere un menu dinamico, che si aggiorna con tutti i record che contengono la stringa digitata.

    Si tratta quindi di provare a riposizionarsi sul record precedentemente selezionato prima del requery.
    Ma quando provo a farlo usarlo i vari metodi suggeriti, ottengo un errore. Il metodo funziona solo la prima volta, come potete verificare anche voi.

    Nel database allegato:
    - Si seleziona un cliente dalla relativa combobox
    - Si selezionano almeno due suoi pazienti dalla relativa combobox, che compaiono nella subform. Il focus rimane sull'ultimo paziente immesso.
    - Si seleziona un prodotto clicclando sul pulsante che fa comparire la listbox, poi click sul prodotto scelto.
    - Il prodotto viene aggiunto nella relativa subform.
    - Si ripete il processo di selezione del prodotto
    - Si ottiene l'errore

    In sostanza: qualsiasi requery io effettuo su uno dei controlli della maschera principale fa perdere il focus sul record della subform.
  • Re: Ritorrno al record selezionato in precedenza

    E' ovvio.... non memorizzi la PK prima di effettuare il Requery della ListBox o ComboBox... cosa ti aspetti...?
    Tu memorizzi e funziona quando fai l'AddNEw, e poi il Riferimento a LastModified viene rilasciato...

    Devi attivare una Funzione da richiamare quando fai il Requery di un Oggetto DataBound che memorizza prima la PK, fa il Requery dell'oggetto e poi ripristina il Record.
  • Re: Ritorrno al record selezionato in precedenza

    Nella maschera principale ho un casella di testo txtLink che memorizza la PK del record evidenziato nella subform.
    Prima di fare il requery utilizzo una variabile lngIDIntestazione a cui assegno il valore in questione. Poi provo a ripristinarlo dopo il requery.
    Come ho fatto qui:
    Private Sub cmdCerca_Click()
        Dim lngIDIntestazione As Long
        Dim StrProd As String
        Dim rst As DAO.Recordset
       
       'Memorizzo l'ID 
        lngIDIntestazione = Me.txtLink
        Me.txtCerca.SetFocus
        
        Set rst = Me.subfrmPazientiFrmNuovaPrestazione.Form.RecordsetClone
        
    
        Me.lstProdotti.Requery
        Me.lstProdotti.Visible = True
        
        'Ripristino il focus sul record
        Me!subfrmPazientiFrmNuovaPrestazione.SetFocus
       rst.FindFirst "[IDIntestazionePrestazione]=" & lngIDIntestazione
        Me!subfrmPazientiFrmNuovaPrestazione.Form.Bookmark = rst.Bookmark
    
        Set rst = Nothing
    End Sub
    Proverò però come consigli a gestire il tutto da una funzione, ma non capisco qual è la differenza.
  • Re: Ritorrno al record selezionato in precedenza

    Ma a cosa serve quella TextBox...? Come la Valorizzi...?
    Se cambi Record come aggiorni il valore della txtBox...?

    E se invece di usare la textbox usassi il controllo associato alla PK non è meglio...?
    Ripeto... scrivere codice è una sfida a togliere non a mettere.
Devi accedere o registrarti per scrivere nel forum
18 risposte