ACCESS在Form.DefaultView=2的数据表类型窗体上怎样访问选中的多列

何尧 345 信誉分
2026-06-15T10:47:54.27+00:00

通过Form.SelTop和Form.SelHeight获得所选行集没有问题,但是怎样通过FormSelLeft和Form.SelWidth获得列的这个问题,在折腾了两天以后,发现终究还是要提问,可能功底不够扎实。

1.打开一个Form.DefaultView=2的数据表类型窗体,有多行多列。

2.已经知道Form.SelWidth表示选中的总列数,也知道FormSelLeft-2=从左到右的实际显示次序,当中都包括隐藏列在内。


问题1:已经选中了窗体上的其中三行三列的矩形,在这种选中状态下,怎样用VBA代码获得第二、三列的控件名。

问题2:如果要实现无需用户选择,而由VBA代码根据当前位置自动选中所需的列数,例如光标在.ActiveControl,并且将要连续选中三列,那么首先选中第一列即.ActiveControl本身的组合键击是什么?因为当.ActiveControl空字符时,本该连续选中下一列的SendKeys "+{RIGHT}",结果是将光标跳到下一列。

Microsoft 365 和 Office | Access | 家庭版 | Windows
0 个注释 无注释

问题作者接受的答案

Gabriel-N 18,875 信誉分 Microsoft 外部员工 审查方
2026-06-15T15:38:36.2433333+00:00

注:此回复已自动翻译。因此,它可能包含语法错误或表达尴尬。

你好 @何尧

为了在数据表选择中正确识别第2列和第3列,尤其是在列被隐藏或重新排序时,我避免直接依赖SelLeft,而是使用了ColumnOrder。逻辑如下:

把SelLeft调整为0起始的数据索引:

用一个辅助函数来:

  • 只筛选可见控件(ColumnHidden = False)
  • 按ColumnOrder排序(实际显示顺序)
  • 返回请求位置的控件名称

然后:

  • 第2列 > leftIdx + 1
  • 第3列 > leftIdx + 2
Sub GetSelectedColumnNames()
   Dim frm As Form: Set frm = Screen.ActiveForm
   Dim leftIdx As Long
   Dim ctrlName2 As String, ctrlName3 As String
  
   If frm.SelWidth < 2 Then
       MsgBox "Please select AT LEAST 2 or 3 columns!", vbInformation
       Exit Sub
   End If
   leftIdx = frm.SelLeft - 2
   Debug.Print "--- NEW TEST RUN (Strictly Position 2 & 3 Only) ---"

   ctrlName2 = GetControlNameAtDataColumn(frm, leftIdx + 1)
   Debug.Print "  Position 2 (SelLeft=" & (frm.SelLeft + 1) & "): " & ctrlName2

   If frm.SelWidth >= 3 Then
       ctrlName3 = GetControlNameAtDataColumn(frm, leftIdx + 2)
       Debug.Print "  Position 3 (SelLeft=" & (frm.SelLeft + 2) & "): " & ctrlName3
   End If
End Sub
Function GetControlNameAtDataColumn(frm As Form, dataIdx As Long) As String
   Dim ctrl As Control
   Dim arrNames() As String, arrOrders() As Long
   Dim count As Long: count = 0
   For Each ctrl In frm.Controls
       If ctrl.ControlType = acTextBox Or ctrl.ControlType = acComboBox Or ctrl.ControlType = acCheckBox Then
           If ctrl.ColumnHidden = False Then
               ReDim Preserve arrNames(count)
               ReDim Preserve arrOrders(count)
               arrNames(count) = ctrl.Name
               arrOrders(count) = ctrl.ColumnOrder
               count = count + 1
           End If
       End If
   Next ctrl
   Dim a As Long, b As Long
   Dim tempOrder As Long, tempName As String
   For a = 0 To count - 2
       For b = a + 1 To count - 1
           If arrOrders(a) > arrOrders(b) Then
               tempOrder = arrOrders(a): arrOrders(a) = arrOrders(b): arrOrders(b) = tempOrder
               tempName = arrNames(a): arrNames(a) = arrNames(b): arrNames(b) = tempName
           End If
       Next b
   Next a
   If dataIdx >= 0 And dataIdx < count Then
       GetControlNameAtDataColumn = arrNames(dataIdx)
   Else
       GetControlNameAtDataColumn = "[Out of Bounds / Hidden]"
   End If
End Function

对于问题2,不使用通过 SendKeys 的键盘快捷键(在进入空单元格编辑模式时会失败),这种方法是直接将选定边界强制写入表单属性。

Sub AutoSelectThreeColumns()
   On Error Resume Next
   If Screen.ActiveControl Is Nothing Then Exit Sub
   Dim currentCtrl As Control, startPos As Long
   Set currentCtrl = Screen.ActiveControl
   ' Get the visual position of the active control
   If currentCtrl.ColumnOrder = 0 Then
       Dim otherCtrl As Control
       startPos = 1
       For Each otherCtrl In Me.Controls
           If (otherCtrl.ControlType = acTextBox Or otherCtrl.ControlType = acComboBox Or otherCtrl.ControlType = acCheckBox) Then
               If otherCtrl.Left < currentCtrl.Left Then startPos = startPos + 1
           End If
       Next otherCtrl
   Else
       startPos = currentCtrl.ColumnOrder
   End If
   ' Force Access UI to natively draw a 3-column highlight instantly
   Me.SelLeft = startPos
   Me.SelWidth = 3      
   Set currentCtrl = Nothing
End Sub

希望这些信息对你有帮助,并能指引你走上正确的方向。请随意尝试一下,如果与你的情况不符,请告诉我。


注意:如果您希望收到本帖相关的邮件通知,请按照我们文档中的步骤启用电子邮件通知。

此答案是否有帮助?

1 个人认为此答案很有帮助。

0 个其他答案

排序依据: 非常有帮助

你的答案

提问者可以将答案标记为“已接受”,审查方可以将答案标记为“已推荐”,这有助于用户了解答案是否解决了提问者的问题。