以父表单

时间:2017-08-19 17:08:32

标签: forms ms-access subforms

好的帮派,我不知所措。似乎有几种方法可以过滤子表单,但是我很少使用它们,但是没有一种方法能够处理多个实例。

这就是我想要完成的事情(这是我的VBA老板与我的梦幻足球神经碰撞时)。

我有一个Fantasy Football Auction Draft数据库,可以从FantasyPros中获取玩家统计数据,等级,值等等。

主要表单允许我跟踪实时草稿。在购买玩家时,会记录交易并与经理联系。

数据库的“Meat”是frm_ManagerBox。此表单Screen shot here正在提取大约16个查询的数据,但主记录源是Manager表。

frm_ManagerBox作为一个独立的表单工作正常,我可以滚动浏览记录(我们联盟中有12位经理)没有问题。

我的目标是拥有一个包含12个frm_ManagerBox实例的主父表单(frm_ProfileHub),每个实例都过滤到12个联盟经理中的一个。理想情况下,我有一个带有12个盒子的大型表格,每个盒子下面都有一个组合框,可以将子表单填充到相应的管理器中。

但是,一旦我尝试嵌入子表单,它就会变成废话。子表单的查询都中断(在表单加载时,我得到16个弹出窗口,询问每个源的定义)。

我的理解是子表单中的查询必须从父表单调用数据。我可以手动设置子表单的每个查询的条件以从父组合框中提取,但这不会解释我在父表单上需要的其他11个实例。

任何帮助或指导将不胜感激。选秀日即将到来! 谢谢!

2 个答案:

答案 0 :(得分:0)

链接字段预备

链接主字段和链接子字段(链接字段)定义子窗体记录源和父记录之间的基本绑定。换句话说,如果子窗体应自动更新以在父窗体导航到新记录时仅显示相关记录,则“链接”字段将指定此过滤。当父级和子级具有明确定义的主键和外键对时,这种内置子表单绑定非常有效,没有麻烦。在规范良好的数据库中,密钥对通常是单字段编号ID。一个例子是:

Link Master Fields:  ID 
Link Child Fields:   ParentID

然而,父和子查询通过多个字段相关是完全合理的。 “链接”字段也支持此功能。多个字段名由分号分隔。另一个例子:

Link Master Fields:  Title;TrxDate
Link Child Fields:   GroupTitle;TrxDate

子表单也可以独立于父表单的记录源,或者父表单甚至可能没有记录源 - 充当未绑定元素和子表单的静态容器。换句话说,不需要基于父记录导航自动过滤子表单。在这种情况下,Link字段设置为空字符串。

在运行时设置RecordSource属性

虽然通常在设计时指定表单记录源,但这不是必需的。在各种情况下,有时在运行时设置记录源是有用的和/或必要的,例如

  • 应根据未绑定的控制值过滤子表单。
  • 子表单旨在显示来自相似(相同字段和数据类型)但不同查询或表的记录。
  • 同一表单将是同一父表单上多个子表单控件的源对象。

在运行时设置子窗体RecordSource属性时,最好立即设置LinkMasterFields和LinkChildFields属性。即使Link字段应为空(即未定义),也是如此。这是因为如果确定父表单的记录源和子表单的记录源具有兼容字段,Access将自动定义链接字段。有时它会根据索引和关系猜对,但有时会定义不需要的和伪造的Link字段,所以最好明确地设置它们。

话虽如此,设置子表单记录源的方法是否指定了链接字段实际上是单独的问题。任何一个方面的方法都是通过满足不同的要求来定义的。

<强>实施例

设置子窗体的RecordSource属性的时间和位置取决于子窗体应如何根据父窗体的其他因素进行过滤。也许有共同的模式,但除此之外没有特别的要求或明确的方法。仅作为一个例子,我将提到几种可能性。

如果在加载父表单时已知所有变量,则在Form_Load()事件处理程序中设置子表单的RecordSource可能就足够了。例如,假设您有一个父表单来管理音乐播放列表。您希望单独显示公共和私人播放列表,但它们具有相同的属性/字段。您创建一个包含所有播放列表字段的表单,然后将两个子表单控件添加到主表单并将每个源对象设置为相同的播放列表表单。现在,您在父窗体上定义以下内容:

'* ---------------------------------------------------
'* In the subform's module

Private Sub SetRecordSource(visibility as String)
    Me.RecordSource = "SELECT * FROM PlayLists WHERE [Visbility] = '" & visibility & "'"
End Sub

Public Sub SetPublicRecordSource()
    SetRecordSource "Public"
End Sub

Public Sub SetPrivateRecordSource()
    SetRecordSource "Private"
End Sub

'* ---------------------------------------------------
'* In the parent form's module

Private Sub Form_Load()
    '* I personally like using strongly-typed local variables
    '* to enhance compile-time error checking and to facilitate Intellisense 
    Dim subform as Form_Playlist

    With Me.PrivatePlaylistSubform
        Set subform = .Form
        subform.SetPrivateRecordSource
        .LinkMasterFields = "ID"
        .LinkChildFields = "PersonID"
    End With            

    With Me.PublicPlaylistSubform
        Set subform = .Form
        subform.SetPublicRecordSource
        .LinkMasterFields = "ID"
        .LinkChildFields = "PersonID"
    End With        
End Sub

这一切都可以使用像Me.PrivatePlaylistSubform.Form.RecordSource这样的完整引用在Form_Load()事件中编码,但这违背了更好的编程实践。

现在考虑一个更复杂和相关的例子。我只是编写细节,因为问题没有具体说明。在这种情况下,父表单表示特定用户的记录。对于每个用户,多个子表单显示不同&#34;经理&#34;的统计信息。只为子表单创建一个表单,因此需要在运行时为多个子表单控件实例设置RecordSource属性。

如果多个&#34;经理&#34;预定义 - 可能存储在可以在RecordSource查询中连接的数据库表中,在特定查询中添加适当的连接和/或引用会相当简单。但我们会更进一步,让每个用户动态选择经理。因此,每个子表单都有一个相应的ComboBox,用于从可用的管理器中进行选择。

老实说,这可以用与上一个例子几乎相同的方式完成。这是父窗体上Form_Load事件处理程序的快速而肮脏的显示。它使用两个功能来过滤每个子表单:1)链接字段和2)引用父表单上的特定控件。

Private Sub Form_Load()
    '* ManagerBox# are all subform controls
    '* comboManagers# are ComboBoxes corresponding to each subform
    '* Both the parent form and each child form's record source has a UserID field.
    '* frm_ProfileHub is the name of the parent form.

    With Me.ManagerBox1
        .Form.RecordSource = "SELECT * FROM UserManagers" & _ 
            " WHERE ManagerID = [Forms]![frm_ProfileHub]![comboManager1]"
        .LinkMasterFields = "UserID"
        .LinkChildFields = "UserID"
    End With            

    With Me.ManagerBox2
        .Form.RecordSource = "SELECT * FROM UserManagers" & _
            " WHERE ManagerID = [Forms]![frm_ProfileHub]![comboManager2]"
        .LinkMasterFields = "UserID"
        .LinkChildFields = "UserID"
    End With            
End Sub

在上面的代码中,我想象ComboBox控件没有绑定到主记录的字段。主userID和manager表之间也有明显的链接。这些都不是这种情况,所以代码可能看起来像

    '* Subform is not directly linked to the primary record
    '* Subform is only filtered by the ComboBox value
    With Me.ManagerBox2
        .Form.RecordSource = "SELECT * FROM Managers" & _
            " WHERE ManagerID = [Forms]![frm_ProfileHub]![comboManager2]"           
        .LinkMasterFields = ""
        .LinkChildFields = ""
    End With

    '* In this case, the comboBoxes are already bound to a parent form's field,
    '*  more specifically to fields labeled [MangerID1], [MangerID2], etc.
    '* So instead of referring to a form control (which is less efficient),
    '* just use the Link fields to handle the binding.
    '* RecordSource is actually identical, so that could be set
    '* at design time and then only update the Link fields at run-time.
    With Me.ManagerBox2
        .Form.RecordSource = "SELECT * FROM UserManagers WHERE"
        .LinkMasterFields = "UserID;ManagerID2"
        .LinkChildFields = "UserID;ManagerID"
    End With

我在许多自己的复杂形式中发现内置的自动绑定功能和表单控件引用 - 虽然编程速度更快 - 在导航过程中可能会相当慢。多个子表单可能已经减慢了父表单的速度,但是如果定义了链接字段并且查询包含对表单控件的直接引用,则表单上的每个trival操作都可能会有过多的刷新。这是另一种方法,只有在更新相关值时,才会将每个RecordSource设置为特定于验证的筛选查询。

'* ---------------------------------------------------
'* In the subform's module

Public Sub SetRecordSource(vUserID As Variant, vManagerID as variant)
    If Not (IsNumeric(vUserID) AND IsNumeric(vManagerID)) Then
        Me.RecordSource = ""
    Else
        Me.RecordSource = "SELECT * FROM UserManagers" & _
            " WHERE UserID = " & vUserID & " AND ManagerID = " & vManagerID
    End If
End Sub

'* ---------------------------------------------------
'* In the parent form's module

Private Sub LinkManagerBox1()
    Dim subform as Form_frm_ManagerBox
    With Me.ManagerBox1
        Set subform = .Form
        subform.SetRecordSource Me.UserID, comboManager1.Value
        .LinkMasterFields = ""
        .LinkChildFields = ""
    End With            
End Sub

Private Sub LinkManagerBox2()
    Dim subform as Form_frm_ManagerBox
    With Me.ManagerBox2
        Set subform = .Form
        subform.SetRecordSource Me.UserID, comboManager2.Value
        .LinkMasterFields = ""
        .LinkChildFields = ""
    End With            
End Sub

Private Sub comboManager1_AfterUpdate()
    LinkManagerBox1
End Sub

Private Sub comboManager2_AfterUpdate()
    LinkManagerBox2
End Sub

Private Sub Form_Current()
    LinkManagerBox1
    LinkManagerBox2
End Sub

答案 1 :(得分:0)

对于原版海报来说可能有点晚了,但是这里的解决方案并不需要VBA并且很容易设置。通过在此处定义过滤器,使用“链接主/子”字段能够将多个字段链接到您的优势。

一个具体的例子。我们假设你正在追踪一个人的行动事项。你有一个名为frmPerson的父表单和一个名为frmActionItems的子表单,它们在PersonId上链接。要设置此父子关系,请使用:

Link Master Fields:  personId
Link Child Fields:   personId

现在,让我们说你决定要两个frmActionItems子表单 - 一个用于显示所有当前活动的操作项,另一个用于显示所有已完成的操作项。操作项表上有一个必需的isCompleted是/否字段。

首先,在frmPerson表单中添加两个不可见的文本框 - 让我们将它们称为txtIsActive和txtIsCompleted。这两个文本框应该是未绑定的,但是将txtIsActive的默认值设置为=False,将默认值设置为txtIsCompleted为=True

将显示用于显示活动操作项的子表单,如下所示:

Link Master Fields:  personId;txtIsActive
Link Child Fields:   personId;isCompleted

...并且因为txtIsActive是false,子表单只会显示其isCompleted值为false的记录,因此那些处于活动状态的记录。同样,我们用于显示已完成的操作项的子表单将链接如下:

Link Master Fields:  personId;txtIsCompleted
Link Child Fields:   personId;isCompleted

原始海报本可以为他的场景设置类似的东西,但有更多隐藏的,未绑定的控件。

相关问题