10

我有一个包含数据表的表格。我想让用户可以选择多行,单击一个按钮并运行一些 sql 查询并对这些行执行一些工作。

查看我的 VBA 代码,我了解如何使用 CurrentRecord 属性访问最后选择的记录。但是我不知道如何知道在多项选择中选择了哪些行。(我希望我很清楚......)

这样做的标准方法是什么?访问 VBA 文档在网上有些晦涩难懂...

谢谢!

4

9 回答 9

10

这是执行此操作的代码,但有一个问题。

Private Sub Command1_Click()
     Dim i As Long
     Dim RS As Recordset
     Dim F As Form

     Set F = Me.sf.Form
     Set RS = F.RecordsetClone

     If F.SelHeight = 0 Then Exit Sub

     ' Move to the first selected record.
     RS.Move F.SelTop - 1

     For i = 1 To F.SelHeight
       MsgBox RS![myfield]
       RS.MoveNext
     Next i

End Sub

这里有一个问题: 如果代码被添加到一个按钮,一旦用户单击该按钮,选择就会丢失在网格中(selheight 将为零)。因此,您需要捕获该信息并将其与计时器或表单上的其他事件一起保存到模块级变量中。

这是一篇文章,详细描述了如何解决问题。
http://www.mvps.org/access/forms/frm0033.htm

Catch 2:这只适用于连续的选择。他们不能在网格中选择多个非连续行。

更新:
可能有一个更好的事件来捕获这个,但这是一个使用我测试过的 form.timerinterval 属性的工作实现(至少在 Access 2k3 中,但 2k7 应该可以正常工作)

此代码进入 SUBFORM,使用该属性获取主窗体中的 selheight 值。

Public m_save_selheight As Integer

Public Property Get save_selheight() As Integer
    save_selheight = m_save_selheight
End Property

Private Sub Form_Open(Cancel As Integer)
    Me.TimerInterval = 500
End Sub

Private Sub Form_Timer()
    m_save_selheight = Me.selheight
End Sub
于 2009-11-03T21:02:12.917 回答
10

我使用了类似于 JohnFx 的技术

为了在选择高度消失之前捕获它,我在主窗体中使用了子窗体控件的 Exit 事件。

所以在主窗体中:

Private Sub MySubForm_Exit(Cancel As Integer)

  With MySubForm.Form
    m_SelNumRecs = .SelHeight
    m_SelTopRec = .SelTop
    m_CurrentRec = .CurrentRecord
  End With

End Sub
于 2009-11-03T22:32:32.763 回答
2

我之前尝试过这样做,但我从未成功使用要求用户选择与 Windows 文件对话框相同样式的多行(按 Ctrl、Shift 等)的方法。

我使用的一种方法是使用两个列表框。用户可以双击左侧列表框中的项目,或者在选择项目时单击按钮,它将移动到右侧列表框。

另一种选择是使用一个本地表,该表中填充了您的源数据以及在子表单中表示为复选框的布尔值。在用户通过单击复选框选择他们想要的数据后,用户按下一个按钮(或其他一些事件),此时您直接转到基础数据表并仅查询那些被选中的行。我认为这个选项是最好的,尽管它需要一些代码才能正常工作。

即使在 Access 中,我发现有时直接使用表和查询比尝试使用 Access 表单中的内置工具更容易。有时内置工具并不能完全满足您的要求。

于 2009-11-03T20:43:33.347 回答
2

当子表单失去焦点时选择丢失的解决方法是将选择保存在 Exit 事件中(正如其他人已经提到的)。

一个很好的补充是使用计时器立即恢复它,以便用户仍然能够看到他所做的选择。

注意:如果您想在按钮处理程序中使用选择,则选择可能在执行时尚未恢复。确保使用变量中保存的值或在按钮处理程序的开头添加一个 DoEvents 以让计时器处理程序首先执行。

Dim m_iOperSelLeft As Integer
Dim m_iSelTop As Integer
Dim m_iSelWidth As Integer
Dim m_iSelHeight As Integer

Private Sub MySubForm_Exit(Cancel As Integer)

    m_iSelLeft = MySubForm.Form.SelLeft
    m_iSelTop = MySubForm.Form.SelTop
    m_iSelWidth = MySubForm.Form.SelWidth
    m_iSelHeight = MySubForm.Form.SelHeight

    TimerInterval = 1

End Sub

Private Sub Form_Timer()

    TimerInterval = 0

    MySubForm.Form.SelLeft = m_iSelLeft - 1
    MySubForm.Form.SelTop = m_iSelTop
    MySubForm.Form.SelWidth = m_iSelWidth
    MySubForm.Form.SelHeight = m_iSelHeight

End Sub
于 2011-09-11T22:32:47.227 回答
2

还有另一种解决方案。

只要您松开鼠标按钮,下面的代码就会显示选定的行数。保存这个值就可以了。

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)

        MsgBox Me.SelHeight

End Sub
于 2013-09-13T18:40:09.357 回答
1

在表单中使用全局变量,然后在按钮代码中引用它。

Dim g_numSelectedRecords as long

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
   g_numSelectedRecords = Me.SelHeight
End Sub


Dim formRecords As DAO.Recordset
Dim i As Long

Set formRecords = Me.RecordsetClone

' Move to the first record in the recordset.
formRecords.MoveFirst

' Move to the first selected record.
formRecords.Move Me.SelTop - 1

For i = 1 To numSelectedRecords
    formRecords.Edit
    formRecords.Fields("Archived") = True
    formRecords.Update
    formRecords.MoveNext
Next i
于 2012-01-06T16:47:17.133 回答
0

为什么不使用数组或记录集,然后每次用户单击一行时(无论是否连续,将该行或某个标识符保存到记录集中。然后当他们单击父窗体上的按钮时,只需迭代记录集保存以做你想做的事。只是不要忘记在单击按钮后清除数组或记录集。?

于 2014-12-03T13:40:58.390 回答
0

在尝试执行过程时保持选择的另一种解决方法 - 无需离开数据表来激活按钮,只需使用 OnKeyDown 事件并定义特定的键码和 shift 组合来执行您的代码。

于 2015-05-05T16:22:12.397 回答
-1

JohnFx 提供的代码运行良好。我以这种方式在没有计时器的情况下实现了它(MS-Access 2003):
1- 将表单的键预览设置为是
2- 将代码放入函数中
3- 设置事件 OnKeyUp 和 OnMouseUp 以调用该函数。

Option Compare Database
Option Explicit

Dim rowSelected() As String

Private Sub Form_Load()
'initialize array
ReDim rowSelected(0, 2)
End Sub

Private Sub Form_Current()
' if cursor place on a different record after a selection was made 
' the selection is no longer valid
If "" <> rowSelected(0, 2) Then
  If Me.Recordset.AbsolutePosition <> rowSelected(0, 2) Then
    rowSelected(0, 0) = ""
    rowSelected(0, 1) = ""
    rowSelected(0, 2) = ""
  End If
End If
End Sub

Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
rowsSelected
If KeyCode = vbKeyDelete And Me.SelHeight > 0 Then
    removeRows
End If
End Sub

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
rowsSelected
End Sub

Sub rowsSelected()
Dim i As Long, rs As DAO.Recordset, selH As Long, selT As Long
selH = Me.SelHeight
selT = Me.SelTop - 1
If selH = 0 Then
    ReDim rowSelected(0, 2)
    Exit Sub
Else
    ReDim rowSelected(selH, 2)
    rowSelected(0, 0) = selT
    rowSelected(0, 1) = selH
    rowSelected(0, 2) = Me.Recordset.AbsolutePosition ' for repositioning 
    Set rs = Me.RecordsetClone
    rs.MoveFirst ' other key touched caused the pointer to shift
    rs.Move selT
    For i = 1 To selH
        rowSelected(i, 0) = rs!PositionNumber
        rowSelected(i, 1) = Nz(rs!CurrentMbr)
        rowSelected(i, 2) = Nz(rs!FutureMbr)
        rs.MoveNext
    Next
    Set rs = Nothing
    Debug.Print selH & " rows selected starting at " & selT 
End If
End Sub

Sub removeRows()
' remove rows in underlying table using collected criteria in rowSelected()
    Me.Requery
' reposition cursor
End Sub

Private Sub cmdRemRows_Click()
If Val(rowSelected(0, 1)) > 0 Then
    removeRows
Else
    MsgBox "To remove row(s) select one or more sequential records using the record selector on the left side."
End If
End Sub
于 2017-07-14T13:31:06.153 回答