同步访问屏幕行上的两个数据表

Posted

技术标签:

【中文标题】同步访问屏幕行上的两个数据表【英文标题】:Synchronize Access two datasheets on screen rows 【发布时间】:2015-03-05 05:26:35 【问题描述】:

我使用子表单数据表模式来显示表格。如果我只使用一个子表单,表格会很宽。我将字段划分为几个组。每个组将由一个子表单显示,每个子表单将位于选项卡控件的选项卡中。如何同步屏幕行上的每个子表单?例如,用户滚动子表单 A 和第 12~23 行现在在屏幕上,而第 15 行被选中。我可以将屏幕上的其他子窗体设置为第 12~23 行并且也选择第 15 行吗?表示所有子窗体显示行和选中行同步。

【问题讨论】:

【参考方案1】:

在主窗体上,放置一个文本框,例如 txtSyncSubforms。

将此控制源应用到它:

=SyncSubforms([subControlFirst]![ID],[subControlSecond]![ID], .., [subControlLast]![ID])

将 subControlxxxx 和 ID 替换为子表单控件的实际名称和 ID,当然,ID 必须是唯一的。

在表单后面添加以下代码:

Option Compare Database
Option Explicit

' Automatic synchronizing of multiple subforms.
' 2019-01-05. Gustav Brock, Cactus Data ApS, CPH.
' Version 1.2.0
' License: MIT.

    ' Index for Split to separate the name of the subform control from
    ' the name of the control with the key.
    '   [subControlAny]![ID]
    ' will be split into:
    '   [subControlAny]
    ' and:
    '   [ID]
    Enum ControlName
    SubForm = 0
    Key = 1
    End Enum

Private Function SyncSubforms(ParamArray sControls() As Variant) As Variant

' Array sControls() holds the values of the key controls on the subform controls
' to be held in sync.

    ' Name of visible textbox on main form bound to this function.
    Const cControl  As String = "txtSyncSubforms"

    ' Static to store the value of the key of the last synced record.
    Static wLastID  As Variant

Dim rst         As DAO.Recordset
Dim wSubform    As Form

' Array to hold the names of the subform controls and key controls.
Dim aControls() As String

Dim bmk         As Variant
Dim wNew        As Boolean
Dim wThisID     As Variant
Dim wIndex      As Integer
Dim wItem       As Integer
Dim wCount      As Long
Dim wFieldName  As String

' If any key value is Null, we have moved to a new record.
' No syncing shall take place.
For wIndex = LBound(sControls()) To UBound(sControls())
    wThisID = sControls(wIndex).Value
    If IsNull(wThisID) Then
        If sControls(wItem).Parent.Name = Me.ActiveControl.SourceObject Then
            ' New record. Don't sync.
            wNew = True
            Exit For
        End If
     ElseIf IsNull(wLastID) Or Me.ActiveControl.Form.NewRecord Then
        ' Initial opening of form, or new record has been created.
        ' Set wLastID to the value of the current key of the first subform
        ' or to the key of the new record.
        wLastID = wThisID
        ' Stop further processing.
        wNew = True
        Exit For
ElseIf IsEmpty(wThisID) Then
        ' Record has been deleted.
        ' Pull the ID from the active subform.
        For wItem = LBound(sControls) To UBound(sControls)
          If sControls(wItem).Parent.Name = Me.ActiveControl.SourceObject Then
              wThisID = Me.ActiveControl(sControls(wItem).Name).Value
' Store as the current key.
wLastID = wThisID
Exit For
            End If
          Next
Exit For
        ElseIf wThisID <> wLastID Then
            ' This key is the new value to sync the other subforms to.
            ' Store the current key.
            wLastID = wThisID
            Exit For
          End If
        Next

If wNew = True Then
    ' New record or initial opening. Do nothing.
Else
    ' ControlSource of cControl will read like:
    '   =SyncSubforms([subControlFirst]![ID],[subControlSecond]![ID], .., [subControlLast]![ID])
    '
    ' Build array of the names of the subform controls with the key controls:
    '   [subControlFirst]![ID]
    '   [subControlSecond]![ID]
    '   ...
    '   [subControlAny]![ID]
    '   ...
    '   [subControlLast]![ID]
    ' by extracting arg names between "(" and ")".
    aControls = Split(Replace(Split(Me(cControl).ControlSource, "(")(1), ")", ""), ",")

    ' Get current record count as it will change after an append or delete in one of the subforms.
    For wIndex = LBound(aControls()) To UBound(aControls())
      If Me(Split(aControls(wIndex), "!")(ControlName.SubForm)).Name = Me.ActiveControl.Name Then
      Set wSubform = Me(Split(aControls(wIndex), "!")(ControlName.SubForm)).Form
      wCount = wSubform.RecordsetClone.RecordCount
      Exit For
    End If
Next

' Loop to locate and sync those subforms that haven't changed.
For wIndex = LBound(aControls()) To UBound(aControls())
    ' Extract name of subform control using Split:
    '   [subControlAny]
    Set wSubform = Me(Split(aControls(wIndex), "!")(ControlName.SubForm)).Form
    If wCount <> wSubform.RecordsetClone.RecordCount Then
       ' A record has been added or deleted in another subform.
       wSubform.Requery
    End If
    If IsNull(sControls(wIndex)) Or sControls(wIndex) <> wThisID Then
      ' This subform is to be synced.
      Set rst = wSubform.RecordsetClone
      ' Find record for current key.
      ' Extract name of control on subform using Split:
      '   [ID]
      ' Then use ControlSource to get the name of the field to search.
      wFieldName = wSubform(Split(aControls(wIndex), "!")(ControlName.Key)).ControlSource
      ' Wrap the fieldname in brackets in case it should contain spaces or special characters.
      If Left(wFieldName, 1) <> "[" Then
        wFieldName = "[" & wFieldName & "]"
     End If
     rst.FindFirst wFieldName & " = " & wThisID
     If Not rst.NoMatch Then
        bmk = rst.Bookmark
        wSubform.Bookmark = bmk
     End If
     rst.Close
    End If
Next

End If

Set rst = Nothing
Set wSubform = Nothing

SyncSubforms = wLastID

End Function

下载完整的文档和演示在这里: Synchronizing Multiple Subforms in Access

【讨论】:

该解决方案似乎有效。但是,我不能让它工作。你能传递一个示例工作文件吗? 事实上我有。配有指南。上面插入了链接。 非常感谢。它完美地工作。还有一个额外的问题:是否可以同步屏幕记录上的所有子表单?例如,当第一个子窗体显示记录 10~21 时,每个子窗体将是相同的记录 10~21。 这并不容易,因为同步的子表单不知道它们同步到的子表单的记录的物理位置。此外,您可以使用鼠标和键盘浏览记录。这会很好,但我发现用户最关心的是,记录是可见的和视觉标记的。所以我不会说,这是不可能的,只是不值得努力。 谢谢,你的 cmets 是有效的。

以上是关于同步访问屏幕行上的两个数据表的主要内容,如果未能解决你的问题,请参考以下文章

结果页面上的空白屏幕:它去了哪里?

将数据属性放在 DataTables 1.10 上的行上

命令行上的数据科学第二版 二开始

动态创建的 html 表格行上的单行选择

登录屏幕上的文件夹访问

Java同步锁