如何从 VBA 表单中编辑要交互选择的记录?

发布于 2024-07-16 03:55:04 字数 371 浏览 4 评论 0原文

我在 MS Access 2003 DB 中有一组 ComboBox,它们都绑定到单个表中的字段。 但是,它们允许您选择的数据并非来自该表,而是来自各种其他表。 这对于记录创建故事来说效果很好,但现在我希望能够追溯地编辑记录。 问题是我无法弄清楚如何在不编写一堆自定义代码的情况下重新填充表单元素。

我最初的想法是提供一个组合框来限制您对记录 ID 的选择,然后执行自定义查询并使用它来设置所有不同表单元素中的选定值。 但是,我觉得我应该能够做一些像 DoCmd.GoToRecord , , , ID 这样简单的事情,并且表单应该可以很好地重新填充。 我并不反对做这些忙碌的工作,但我确信我只是在我相对薄弱的 VBA 和 Access 知识中遗漏了一些东西。

I have a set of ComboBox's in an MS Access 2003 DB that are all bound to fields in a single table. However, the data that they allow you to select doesn't come from that table and instead comes from various other tables. This works fine for the record creation story but now I want to be able to edit the record retroactively. The problem is that I can't figure out how to refill the form elements without writing a bunch of custom code.

My initial inclination is to provide a combo box that limits your choices to record IDs and then do a custom query and use that to set the selected values in all of different form elements. However, I feel like I should be able to do something as simple as DoCmd.GoToRecord , , , ID and the form should repopulate just fine. I'm not opposed to doing the busy work but I'm sure I'm just missing something in my relatively puny knowledge of VBA and Access.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

深爱成瘾 2024-07-23 03:55:04

为了增加这种组合,我会提供两种方法,一种是推荐的,另一种是不推荐的。

方法 1:如果您已将表单绑定到整个数据表(这是不推荐的方法),您可以使用组合框向导导航到请求的记录,但我不建议在最新版本的访问:

A. 它不允许您在创建代码之前正确命名组合框。

b. 代码是错误的。

这是我刚刚在测试数据库中生成的代码:

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

这在很多方面都是错误的,但它非常引人注目。 代码应该是这样的:

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

当 RecordsetClone 已经存在时,无需克隆表单的记录集。

当您可以直接使用预先存在的对象时,没有理由使用对象变量。

在离开记录之前需要检查脏记录,因为如果不强制保存,保存过程中的错误可能会导致数据丢失。

但更好的方法是:

方法 2:使用组合框更改表单的基础记录源。

组合框的 AfterUpdate 事件看起来像这样:

If Not IsNull(Me!cmbMyComboBox) Then
   Me.Recordsource = Me.Recordsource & " WHERE [ID]=" & Me!cmbMyComboBox
End If

现在,这只在第一次时有效,因为在第二次重置 Recordsource 时,您最终会得到两个 WHERE 子句,这不好。 有两种方法

: 假设表单在没有 WHERE 子句的情况下打开,则将打开的记录源值存储在表单的 OnLoad 事件中的模块级变量中:

   Private Sub Form_Load()
     strRecordsource = Left(Me.Recordsource,Len(Me.Recordsource)-1)
   End Sub

在模块级别,相应地定义 strRecordsource:

   Dim strRecordsource As String

然后在组合框的 AfterUpdate 事件中,您可以使用以下内容:

   Me.Recordsource = strRecordsource & " WHERE [ID]=" & Me!cmbMyComboBox

现在,如果您的表单打开时已经定义了 WHERE 子句,那么它会变得更加复杂,但我不会深入讨论这一点,并将其作为练习留给读者,最佳方法可能是什么。

Just to add to the mix, I would offer two approaches, one recommended, the other not.

Approach 1: If you've bound your form to the whole data table (this is the non-recommended approach), you can use the combo box wizard to navigate to the requested record, but I wouldn't recommend it in recent versions of Access:

a. it doesn't allow you to properly name the combo box before it creates code.

b. the code is just WRONG.

Here's the code I just produced in my test database:

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

This is wrong in so many ways it's just remarkable. This is what the code should be:

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

There is no need to clone the form's recordset when the RecordsetClone already exists.

There is no reason to use an object variable when you can just directly use the pre-existing object.

There needs to be a check for a dirty record before departing the record because if you don't force the save, errors in the save process can lead to lost data.

But the better approach is this:

Approach 2: Use the combo box to change the form's underlying recordsource.

The AfterUpdate event of your combo box would look something like this:

If Not IsNull(Me!cmbMyComboBox) Then
   Me.Recordsource = Me.Recordsource & " WHERE [ID]=" & Me!cmbMyComboBox
End If

Now, this only works the first time, as on the second resetting of the Recordsource, you end up with two WHERE clauses, which is not good. There are two approaches:

a. assuming that the form opens without a WHERE clause, store the opening recordsource value in a module-level variable in the form's OnLoad event:

   Private Sub Form_Load()
     strRecordsource = Left(Me.Recordsource,Len(Me.Recordsource)-1)
   End Sub

And at the module level, define strRecordsource accordingly:

   Dim strRecordsource As String

Then in the combo box's AfterUpdate event, you have this instead:

   Me.Recordsource = strRecordsource & " WHERE [ID]=" & Me!cmbMyComboBox

Now, if your form opens with a WHERE clause already defined, it gets more complicated, but I'll not go into that and leave it as an exercise to the reader what the best approach might be.

情丝乱 2024-07-23 03:55:04

我假设您已经为每个组合框设置了行源。 只要您没有将组合框限制为该列表即可; 它应该显示您在该列中存储的内容。

但是,如果您的组合框更改了每一行的列表,您可以在记录的 OnCurrent 事件或字段的 GotFocus 事件中执行类似的操作:

Me.combo_box_name.Requery 

I presume that you've already set up the row sources for each combo box. So long as you haven't limited the combo box to that list; it should display what you have stored in that column.

However, if your Combo Box changes its list for each row you can do something like this in the record's OnCurrent event or the field's GotFocus event:

Me.combo_box_name.Requery 
穿透光 2024-07-23 03:55:04

重新阅读您的问题后,我想我明白您想要实现的目标。 尽管在这种情况下我可能会使用 OpenForm,但您使用 GotoRecord 的方向是正确的,因为它有一个 WhereCondition 属性,允许您使用 SQL 准确指定要打开的记录。 听起来您想在表单中实现“跳转到记录”类型的功能,其中用户从列表中选择记录 ID,表单将更改以显示所选记录。

一种可能性是每次用户在组合框中选择一个项目时切换到新记录。 您可以在 ComboBox 的 Click 事件中处理此问题。

我将使用一个简单的示例:假设您有一个 Students 表,以及一个用于查看/编辑 Students 表中记录的 StudentFormStudentForm 有一个 ComboBox cboStudentID,它通过其 RowSource 属性绑定到 Students.ID 列。 当您在 ComboBox 中选择一个学生 ID 时,StudentsForm 将切换显示相应的学生记录。

在 ComboBox 的 Click 事件处理程序中,您可以使用如下代码编写此“跳转到记录”功能:

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

正如 David W. Fenton 在评论中指出的那样,您可以缩短以下行:

recordID = cboStudentID.ItemData(cboStudentID.ListIndex)

到此:

recordID = Me!cboStudentID

或只是:

recordID = cboStudentID

因为在这种情况下 ComboBox 的默认值将是当前 ListIndex 处绑定列的值。 在这种情况下,您可以完全删除 recordID 并对 Click 事件进行编码,如下所示:

Private Sub cboStudentID_Click() 
    DoCmd.OpenForm "StudentForm", WhereCondition:="Student.ID=" & cboStudentID
End Sub

After re-reading your question, I think I see what you are trying to achieve. You're on the right track with GotoRecord, although I would probably use OpenForm in this case, because it has a WhereCondition property that allows you to use SQL to specify exactly what record to open. It sounds like you want to implement a "jump to record" type functionality in your form, where the user selects a record ID from a list and the form changes to display the selected record.

One possibility is to switch to the new record each time the user selects an item in the ComboBox. You can handle this in the ComboBox's Click event.

I'll use a simple example: suppose you have a Students table, and a StudentForm for viewing/editing records in the Students table. The StudentForm has a ComboBox cboStudentID that is bound to the Students.ID column via it's RowSource property. When you select a student ID in the ComboBox, the StudentsForm will switch to display the corresponding student record.

In the Click event handler for the ComboBox, you can code this "jump to record" functionality with something like the following:

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

As David W. Fenton points out in the comments, you can shorten the following line:

recordID = cboStudentID.ItemData(cboStudentID.ListIndex)

to this:

recordID = Me!cboStudentID

or just:

recordID = cboStudentID

since the default value of the ComboBox in this case will be the value of the bound column at the current ListIndex. In this case, you could just remove recordID altogether and code the Click event as follows:

Private Sub cboStudentID_Click() 
    DoCmd.OpenForm "StudentForm", WhereCondition:="Student.ID=" & cboStudentID
End Sub
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文