我有一张包含数据表的表格。我想让用户可以选择多行,单击一个按钮并运行一些SQL查询并对这些行执行一些工作。
查看我的VBA代码,我看到如何使用CurrentRecord属性访问上次选择的记录。但我不知道如何知道在多个选择中选择了哪些行。 (我希望我很清楚......)
这样做的标准方法是什么?访问VBA文档在网上有点模糊......
谢谢!
答案 0 :(得分:9)
我使用的技术类似于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
答案 1 :(得分:8)
这是执行此操作的代码,但有一个问题。
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
答案 2 :(得分:2)
之前我尝试过这样的事情,但是使用一种方法要求用户选择与Windows文件对话框相同的样式(按Ctrl,Shift等)的方法,我从未取得任何成功。
我使用的一种方法是使用两个列表框。用户可以双击左侧列表框中的项目,或者在选择项目时单击按钮,它将移动到右侧列表框。
另一种选择是使用填充了源数据的本地表以及表示为子表单中复选框的布尔值。用户通过单击复选框选择他们想要的数据后,用户按下按钮(或其他一些事件),此时您直接进入基础数据表并仅查询已检查的行。我认为这个选项是最好的,但它需要一些代码才能正常工作。
即使在Access中,我发现有时直接使用表和查询更容易,而不是尝试使用Access表单中的内置工具。有时,内置工具并不能完全满足您的需求。
答案 3 :(得分: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
答案 4 :(得分:2)
还有另一种解决方案。
下面的代码会在您释放鼠标按钮后立即显示所选行的数量。 保存这个值就行了。
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
MsgBox Me.SelHeight
End Sub
答案 5 :(得分: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
答案 6 :(得分:0)
为什么不使用数组或记录集,然后每次用户点击一行(连续或不连续),将该行或某些标识符保存到记录集中。然后当他们单击父表单上的按钮时,只需迭代已保存的记录集可以执行您想要的操作。单击按钮后,不要忘记清除数组或记录集。
答案 7 :(得分:0)
在尝试执行过程时保持选择的另一种解决方法 - 只需使用OnKeyDown事件并定义特定的键码和移位组合来执行代码,而不是让数据表激活按钮。
答案 8 :(得分:-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