在 MS Access 中使用子表单会降低性能吗?

Posted

技术标签:

【中文标题】在 MS Access 中使用子表单会降低性能吗?【英文标题】:Does it degrade performance to use subforms in MS Access? 【发布时间】:2009-09-01 00:17:09 【问题描述】:

我正在考虑在父表单上使用选项卡控件,我希望有大约 20 个选项卡。我正在考虑使用一个或两个单独的子表单的每个选项卡。每个子形式在编码逻辑上都有不同的复杂性。通过采用这种方法,我会分别降低我的应用程序的性能吗?我目前在 MS Access 2003 中使用它。我预计在任何给定时间平均有 15 个用户使用各种表单。

想法?

【问题讨论】:

【参考方案1】:

是的,每个子表单的性能都会略有下降。一三个还不错,但二十肯定会导致性能问题。

一旦您的子表单工作令您满意,要么将记录源保存为查询并为其命名,要么保存查询 SQL 字符串。然后在选项卡控件更改事件的 VBA 代码中粘贴查询名称或查询 SQL 字符串。

Private Sub TabCtl_Change()
   On Error GoTo TabCtl_Change_Error

    Select Case Me.TabCtl.Value
    Case Me.pagPartsConsumed.PageIndex
        If Me.PartsConsumedsbf.Form.RecordSource <> "Equipment - Parts Consumed sbf" Then _
            Me.PartsConsumedsbf.Form.RecordSource = "Equipment - Parts Consumed sbf"
....

现在只是为了确保我不会不小心留下一些子表单记录源填充在启动时减慢应用程序我检查代码正在运行的文件是否是 MDB(而不是 MDE。函数如下)然后显示一条消息,告诉我必须删除记录源。

   If Not tt_IsThisAnMDE Then
        If Me.PartsConsumedsbf.Form.RecordSource <> "" Then _
            MsgBox "Record source of Equipment - Parts Consumed sbf not empty"
        ...
   End If

Public Function tt_IsThisAnMDE()
On Error GoTo tagError

  Dim dbs As Database
  Set dbs = CurrentDb
  Dim strMDE As String
  On Error Resume Next
  strMDE = dbs.Properties("MDE")
  If Err = 0 And strMDE = "T" Then
    ' This is an MDE database.
    tt_IsThisAnMDE = True
  Else
    tt_IsThisAnMDE = False
  End If

    Exit Function

tagError:
    Call LogError(Application.CurrentObjectName, "")
    Exit Function

End Function

在表单卸载事件中,我也清除了记录源。

Private Sub Form_Unload(Cancel As Integer)

   On Error GoTo Form_Unload_Error

    Me.PartsConsumedsbf.Form.RecordSource = ""
    ....

顺便说一句,我几乎总是将每个子表单放在单独的选项卡上。此外,许多选项卡条目在视觉上变得笨拙。当我遇到类似问题时,我的 Access MVP 同事建议使用左侧的列表框来控制可以查看的子表单。

此外,每个组合框和列表框也会稍微降低性能。因此,如果您在子表单上有这些内容,请考虑类似的逻辑。

【讨论】:

谢谢,这很有帮助。我会尝试两者,看看哪个运行得最好。 +1 只是对您的 OnChange 事件的评论:如果您使用标签页名称并获取 .PageIndex,为什么不根据 Me!ctlTab.Pages(Me!ctlTab ).Name,然后每个案例都是“pagPartsConsumed”。显然,您希望避免在页面索引上进行选择,因为当您在选项卡控件中添加/移动页面时,它可能会发生变化。但在我看来,查找一个字符串值比查找 SELECT CASE 的每个 CASE 的 .PageIndex 更简单。可能在性能方面没有什么不同,但对我来说更合乎逻辑。 大卫,你的语法看起来比只使用 Me.pagPartsConsumed.PageIndex 更难看,所以我可能不明白你的评论。【参考方案2】:

除了在运行时添加记录集之外,我通常只会使用一两个选项卡和一些控件来将各种子窗体加载到子窗体控件中。

控件的 On Click 事件的文本可能是:

=WhichPage([Form],"lblLocations")

WhichPage 是一个函数,其中包括以下几行:

Function WhichPage(frm, Optional LabelName = "")
    <..>

    Select Case LabelName

    Case "lblLocations"
        frm("sfrmAll").SourceObject = "sfrmLocations"

<...>

如有必要,可以在运行时更改链接子字段和链接主字段。链接主字段最好设置为控件的名称,而不是字段,以避免错误。

Me.sfrmAll.LinkChildFields = "LocationKey"
Me.sfrmAll.LinkMasterFields = "txtLocationKey"

【讨论】:

这也是我要建议的。使用 ONE 子表单控件并按照您的建议动态加载子表单。意识到这种方法要求子表单不嵌入任何一个选项卡上,而只是覆盖选项卡控件。如果选项卡都需要使用具有不同数据的相同子表单,Tony 的想法是最好的。但是在实际子表单可能不同的情况下,我会使用这种方法。赛斯 我没有覆盖子表单控件,它在一个选项卡上。我可能有几个标签,一般不超过三个,这取决于我在做什么。 非常直接的方法。谢谢!【参考方案3】:

为了扩展 Remou 的答案...这是我编写的一个子组件,它可以将表单动态加载到子表单控件中。您在调用中传入表单的名称,它会将其加载到主表单的子表单中。参数映射到 Access 的 Docmd.OpenForm 方法的参数。如果承载子窗体控件的主窗体未打开...它只是定期打开窗体。否则,它将它加载到子窗体控件中。如果传入了 where 子句,它将用于过滤子表单。

Public Sub MyOpenForm(FormName As String, _
                            Optional View As AcFormView = acNormal, _
                            Optional FilterName As String = vbNullString, _
                            Optional WhereCondition As String = vbNullString, _
                            Optional DataMode As AcFormOpenDataMode, _
                            Optional WindowMode As AcWindowMode, _
                            Optional OpenArgs As String)

On Error GoTo PROC_ERR

Dim frm As Form
Dim strNewForm As String
Dim strCurrentForm As String
Dim strNewTable As String
Dim fDoNotFilter As Boolean
Dim strActionText As String
Dim strID As String

If Not IsLoaded("frmMain") Then
    DoCmd.OpenForm FormName:=FormName, View:=View, FilterName:=FilterName, WhereCondition:=WhereCondition, DataMode:=DataMode, WindowMode:=WindowMode, OpenArgs:=OpenArgs
Else
    strCurrentForm = Forms![frmMain]![sfrMyForm].SourceObject
    If strCurrentForm <> FormName Then
      Forms![frmMain]![sfrMyForm].SourceObject = vbNullString
      Forms![frmMain]![sfrMyForm].SourceObject = FormName
    End If
    If WhereCondition <> vbNullString Then
      Forms![frmMain]![sfrMyForm].Form.Filter = WhereCondition
      Forms![frmMain]![sfrMyForm].Form.FilterOn = True
    End If
End If


PROC_EXIT:
  Exit Sub

PROC_ERR:
  MsgBox Err.Description
  Resume PROC_EXIT

End Sub

【讨论】:

以上是关于在 MS Access 中使用子表单会降低性能吗?的主要内容,如果未能解决你的问题,请参考以下文章

MS Access 子表单的多个分离条件

MS Access - 使用子表单过滤时禁止保存提示

MS Access 子表单数据条目在插入 SQL 时被锁定

MS Access 验证规则未在子表单中触发

如何在连续子表单中使用未绑定复选框 - MS Access 2013

子表单在 MS Access 中的主表单之前打开