J'ai un ensemble de ComboBox dans une base de données MS Access 2003 qui sont tous liés à des champs dans une seule table. Cependant, les données qu'ils vous permettent de sélectionner ne proviennent pas de cette table et proviennent plutôt de diverses autres tables. Cela fonctionne bien pour l'histoire de la création d'enregistrements, mais maintenant je veux être en mesure de modifier l'enregistrement rétroactivement. Le problème est que je ne peux pas comprendre comment remplir les éléments de formulaire sans écrire un tas de code personnalisé. Mon objectif initial est de fournir une zone de liste déroulante qui limite vos choix pour enregistrer les ID, puis de faire une requête personnalisée et de l'utiliser pour définir les valeurs sélectionnées dans tous les différents éléments de formulaire. Cependant, je me sens comme si je devais être capable de faire quelque chose d'aussi simple que DoCmd.GoToRecord , , , ID
et le formulaire devrait repeupler très bien. Je ne suis pas opposé à faire le travail occupé mais je suis sûr que je manque juste quelque chose dans ma connaissance relativement chétive de VBA et d'Access.Comment modifier les enregistrements d'un formulaire VBA que vous souhaitez sélectionner de manière interactive?
Répondre
Je présume que vous avez déjà configuré les sources de ligne pour chaque zone de liste déroulante. Tant que vous n'avez pas limité la liste déroulante à cette liste; il devrait afficher ce que vous avez stocké dans cette colonne.
Cependant, si votre change Combo Box sa liste pour chaque ligne que vous pouvez faire quelque chose comme ça dans le cas OnCurrent enregistrement ou l'événement GotFocus du terrain:
Me.combo_box_name.Requery
Après re-lecture de votre question, je pense que je voyez ce que vous essayez d'accomplir. Vous êtes sur la bonne voie avec GotoRecord
, bien que j'utilise probablement OpenForm
dans ce cas, car il a une propriété WhereCondition
qui vous permet d'utiliser SQL pour spécifier exactement quel enregistrement ouvrir. Il semble que vous souhaitiez implémenter une fonctionnalité de type "Aller à l'enregistrement" dans votre formulaire, où l'utilisateur sélectionne un ID d'enregistrement dans une liste et le formulaire change pour afficher l'enregistrement sélectionné.
Une possibilité consiste à basculer vers le nouvel enregistrement chaque fois que l'utilisateur sélectionne un élément dans la zone de liste déroulante. Vous pouvez gérer cela dans l'événement Click
du ComboBox.
Je vais utiliser un exemple simple: supposons que vous ayez une table Students
et une StudentForm
pour afficher/modifier des enregistrements dans la table Students
. Le StudentForm
a un ComboBox cboStudentID
qui est lié à la colonne Students.ID
via sa propriété RowSource
. Lorsque vous sélectionnez un ID d'étudiant dans la zone de liste déroulante, le StudentsForm
bascule pour afficher le dossier d'élève correspondant.
Dans le gestionnaire d'événements Click
pour la zone de liste déroulante, vous pouvez coder ce « saut pour enregistrer » fonctionnalité avec quelque chose comme ce qui suit:
Private Sub cboStudentID_Click()
Dim recordID As Long
'The ItemData property will return the value of the bound'
'column at the specified index.'
recordID = cboStudentID.ItemData(cboStudentID.ListIndex)
'Jump to the record. This assumes we want to use the same form.'
'You can change the form name if you want to open a different form when'
'the user selects an ID from the ComboBox.'
DoCmd.OpenForm "StudentForm", WhereCondition:="Student.ID=" & recordID
End Sub
Comme David W. Fenton souligne dans les commentaires, vous pouvez raccourcir la ligne suivante:
recordID = cboStudentID.ItemData(cboStudentID.ListIndex)
à ceci:
recordID = Me!cboStudentID
ou tout simplement:
recordID = cboStudentID
puisque la valeur par défaut du ComboBox dans ce cas, sera la valeur de la colonne liée à la ListIndex
actuelle.Dans ce cas, vous pouvez simplement supprimer recordID
tout à fait et le code de l'événement Click
comme suit:
Private Sub cboStudentID_Click()
DoCmd.OpenForm "StudentForm", WhereCondition:="Student.ID=" & cboStudentID
End Sub
Si la colonne ID est la colonne liée (indépendante du fait que la zone de liste déroulante soit liée ou non, c'est-à-dire, ControlSource), la valeur par défaut de la zone de liste déroulante est l'ID et inutile d'utiliser ItemData. Si vous avez besoin d'autre chose que la colonne liée, ItemData est juste le ticket. –
Merci, David. J'ai édité ma réponse pour refléter le fait qu'ils sont équivalents dans ce cas. –
Juste pour ajouter au mélange, je propose deux approches, celle qui est recommandée, l'autre non. Approche 1: Si vous avez lié votre formulaire à l'ensemble de la table de données (c'est l'approche non recommandée), vous pouvez utiliser l'assistant de liste déroulante pour naviguer vers l'enregistrement demandé, mais je ne le recommanderais pas dans les versions récentes d'Access:
a. il ne vous permet pas de nommer correctement la zone de liste déroulante avant de créer du code.
b. le code est juste incorrect.
Voici le code que je viens produisais dans ma base de test:
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[InventoryID] = " & Str(Nz(Me![Combo2], 0))
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
Ceci est faux de tant de façons c'est tout simplement remarquable. C'est ce que le code devrait être:
With Me.RecordsetClone
.FindFirst "[ID]=" & Me!cmbMyComboBox
If Not .NoMatch Then
If Me.Dirty Then Me.Dirty = False
Me.Bookmark = .Bookmark
Else
MsgBox "Not Found!"
End If
End With
Il n'y a pas besoin de cloner le recordset du formulaire lorsque le RecordsetClone existe déjà.
Il n'y a aucune raison d'utiliser une variable d'objet lorsque vous pouvez utiliser directement l'objet préexistant.
Il doit y avoir une vérification pour un enregistrement sale avant de quitter l'enregistrement, car si vous ne forcez pas la sauvegarde, des erreurs dans le processus de sauvegarde peuvent conduire à des données perdues.
Mais la meilleure approche est la suivante:
Approche 2: Utilisez la zone de liste déroulante pour modifier recordsource sous-jacente du formulaire.
L'événement AfterUpdate de votre zone de liste déroulante ressemblerait à quelque chose comme ceci:
If Not IsNull(Me!cmbMyComboBox) Then
Me.Recordsource = Me.Recordsource & " WHERE [ID]=" & Me!cmbMyComboBox
End If
Maintenant, cela ne fonctionne que la première fois, comme sur la deuxième remise à zéro du Recordsource, vous vous retrouvez avec deux clauses WHERE, ce qui n'est pas bon. Il existe deux approches:
a. en supposant que la forme ouvre sans une clause WHERE, stocker la valeur recordsource d'ouverture dans une variable au niveau du module dans l'événement OnLoad du formulaire:
Private Sub Form_Load()
strRecordsource = Left(Me.Recordsource,Len(Me.Recordsource)-1)
End Sub
Et au niveau du module, définir strRecordsource en conséquence:
Dim strRecordsource As String
Puis à l'événement AfterUpdate de la zone de liste déroulante, vous avez ceci:
Me.Recordsource = strRecordsource & " WHERE [ID]=" & Me!cmbMyComboBox
maintenant, si votre formulaire ouvre avec une clause WHERE déjà définie, cela devient plus compliqué, mais je n'entrerai pas là-dedans et je laisserai au lecteur le soin de déterminer quelle pourrait être la meilleure approche.
Trouvé une faute de frappe mineure. Je pense que la ligne "rs.FindFirst ..." après le "With Me.RecordsetClone" dans votre deuxième exemple devrait lire ".FindFirst ...". –
Oh, et +1. N'étant pas un gourou d'Access, je n'ai pas pensé à modifier directement la source d'enregistrements. Beaucoup plus élégant qu'un DoCmd, je pense. Peut-être que c'est juste moi et le fait que je ne fais pas vraiment la programmation Access, mais le recours à DoCmd me semble généralement être un hack (c'est-à-dire qu'il y a habituellement un meilleur moyen). –
Merci pour la faute de frappe - maintenant corrigé. –
Cette question est déroutante, si vous avez un formulaire standard avec des combos standard, il n'y a rien à faire ici, ça devrait juste marcher. – AnthonyWJones
Essayez-vous de mettre à jour les éléments dans chaque zone de liste déroulante, car ils ont changé depuis le formulaire ouvert? – JeffO