Access中连续形式的组合框的自定义行源
Posted
技术标签:
【中文标题】Access中连续形式的组合框的自定义行源【英文标题】:Custom row source for combo box in continuous form in Access 【发布时间】:2008-09-17 18:45:16 【问题描述】:我四处搜索,似乎这是 MS Access 的一个限制,所以我想知道其他人找到了哪些创造性的解决方案来解决这个难题。
如果您有一个连续的表单,并且您希望某个字段成为特定于该行的选项组合框,则 Access 无法交付;组合框行源仅在表单开头查询一次,因此会为表单的其余部分显示错误的选项。
当然,我们都尝试的下一步是使用 onCurrent 事件重新查询组合框,这实际上将选项限制在给定的行中。但是,此时,Access 变得疯狂,并且为每一行重新查询组合框的所有,结果通常是其他行中的选项消失和重新出现,具体取决于它们是否选择了对当前记录的行源有效的选项。
我发现的唯一解决方案是始终列出所有可用选项。有什么创意答案吗?
编辑另外,我应该注意,组合框的原因是有一个查询作为查找表,需要隐藏和存储真正的值,而显示人类可读的版本...组合框行源中的多列。因此,将限制更改为列表并没有帮助,因为不在当前行源查询中的 id 将没有匹配的人类可读部分。
在这种特殊情况下,连续形式很有意义,所以请不要告诉我这是错误的解决方案。我要求任何有创意的答案。
【问题讨论】:
【参考方案1】:我也讨厌 Access,但你必须使用你收到的牌。 连续表单在 Access 中是一件很棒的事情,直到您遇到任何常见的复杂性,例如在本例中。
这是我在遇到这种情况时会做的事情(我之前已经实施过类似的解决方法):
在表单上放置一个 UNBOUND 组合框。然后为要编辑的字段放置一个 BOUND 文本框。
确保组合框隐藏在文本框后面(不是不可见,只是隐藏)。
在 OnCurrent 事件中,用必要的数据填充列表框。继续并“限制列出”它。
在文本框的 OnEnter 或 OnClick 事件中给组合框焦点。这将把组合框带到最前沿。当焦点离开组合框时,它会再次隐藏自己。
在组合框的 AfterUpdate 事件中,将文本框的值设置为等于组合框的值。
根据您的情况,可能还有一些其他细节需要解决,但这应该或多或少地实现您的目标,而不会增加太多复杂性。
【讨论】:
@[Gilligan]:这是一个有趣的想法……我会试一试。我想我必须添加另一个转折点 - 我需要一个隐藏的文本框用于绑定变量,因为它只是一个 id 号,我希望人类可读的版本是可见的。我想我只需要同时更新两者。 @[DGM]:这是一个有趣的转折,因为 textBox 实际上隐藏了为所有行更改的组合框值(我相信)。在这种情况下,您实际上可能需要两个文本框,一个用显示值覆盖组合框,另一个用 ID 隐藏,然后组合框 AfterUpdate 会将可见文本框更改为显示值,将隐藏文本框更改为隐藏值。 如果人类可读的值不是基础查询的一部分,您可以做些什么吗?即,绑定的 id 编号是指另一个表中可以找到人类可读值的项目。我可以创建一个查询来连接必要的表并以此为基础创建表单,但是我失去了编辑的能力。还有什么想法吗? 为确保制表符按预期工作,请将文本框的制表位属性设置为“否”,将组合框设置为“是”。 有没有办法在数据表视图中做到这一点?我遇到了同样的问题,但是在空间限制意味着我必须使用数据表视图的子表单中。【参考方案2】:使用连续形式..绝对。事实上,您可以使用基于连续表单的出色且直观的用户界面构建整个应用程序。不要听吐司!
您列出所有可用选项的解决方案是正确的。事实上,没有其他干净的解决方案。但是,当您说 Access 疯了时,您就错了。在连续表单上,您可以将每一行视为详细信息部分的一个实例,其中组合框是详细信息部分的所有实例共有的属性。您可以为所有实例更新此属性,但不能为一个特定实例设置它。这就是为什么 Access 必须在组合框中为所有记录显示相同的数据!
如果您需要在此组合框中仅接受特定于记录的值,请使用 beforeUpdate 事件添加控制过程。如果无法接受新值,您可以取消数据更新,恢复字段中的先前值。
在链接数据(存储在控件中的数据)被隐藏的情况下,您不能将 limitToList 属性设置为“否”。这是合乎逻辑的:当链接字段(不可见)保持为空时,机器如何接受新数据行的输入?
【讨论】:
【参考方案3】:您还可以将组合框的值设置为不可编辑的文本字段,然后启动弹出/模态窗口来编辑该值。但是,如果我这样做,我可能会倾向于在其中一个窗口中编辑整个记录。
【讨论】:
【参考方案4】:我认为完全不应该谴责 Access 连续表单,但我绝对认为应该避免使用它们来编辑数据。它们非常适用于列表,并为您提供比单纯的列表框更多的格式化功能(当然也更容易使用,尽管它们不允许多选)。
如果您想使用连续表单导航到记录进行编辑,请使用显示详细数据的子表单进行编辑,并将子表单中的 PK 值用于链接字段。这可以通过连续表单来完成,您可以在页眉或页脚中放置一个详细的子表单,链接在连续表单后面的表格的 PK 上。
或者,如果您使用连续表单在父表单中显示子数据,则可以将详细信息子表单与连续子表单中的 PK 引用链接起来,例如:
[MySubForm].[Form]!MyID
这将是链接主属性,而 MyID 将是链接子属性。
【讨论】:
我觉得这种信念很令人不安。 Excel(例如)基于连续、可更新表单的范式!【参考方案5】:我们在应用程序中也经常遇到这种情况。我们发现这是一个很好的解决方案: 只需显示组合框中的所有行。 然后,一旦用户在特定行中输入组合框,就调整行源(使用该行的过滤器)。当组合框失去焦点时,您可以重新设置行源以显示所有内容。
【讨论】:
您能详细说明一下吗?除非我严重误解了您,否则调整当前记录中组合框的行源可以(暂时)删除其他记录中组合框中的选定/可见条目,即该组合框中的条目似乎在某些甚至所有其他记录中消失一旦用户激活当前记录中的组合框。由于我们在这里讨论的是连续表单,通常会同时向用户呈现多条记录,这在大多数情况下是不可接受的。 它确实也会影响其他连续形式的记录。但它和 Access 中的一样好。【参考方案6】:我有一个比 Gilligan 更简单的方法。看起来工作量很大,但实际上并非如此。我的解决方案需要将我的连续表单作为子表单数据表。在我的子表单上,我有两个查找组合框,以及其他字段,称为设备和制造商。两者都只是在数据源中保存一个 Long Integer 键。制造商需要按设备中选择的内容进行过滤。我过滤 Manufacturer.RowSource 的唯一一次是在 Manufacturer_GotFocus 事件中。
私有子厂商_GotFocus()
If Nz(Me.Equipment, 0) > 0 Then
Me.Manufacturer.RowSource = GetMfrSQL() '- gets filtered query based on Equipment
Else
Me.Manufacturer.RowSource = "SELECT MfgrID, MfgrName FROM tblManufacturers ORDER BY MfgrName"
End If
结束子
在 Manufacturer_LostFocus 中,我也将 Manufacturer.RowSource 重置为所有制造商。您需要这样做,因为当您第一次单击子表单时,所有控件(包括制造商)都会触发 GotFocus 事件,即使您实际上并未更新任何字段。
私有子制造商_LostFocus()
Me.Manufacturer.RowSource = "SELECT MfgrID, MfgrName FROM tblManufacturers ORDER BY MfgrName"
结束子
在制造商的输入事件中,您必须检查是否选择了设备,如果没有将焦点设置为设备。
私有子制造商_Enter()
If Nz(Me.EquipmentID, 0) = 0 Then
'-- Must select Equipment first, before selecting Manufacturer
Me.Equipment.SetFocus
End If
结束子
您还需要在Form_Current事件(即Me.Manufacturer.Requery)中重新查询Manufacturer组合框,并且您应该将该子表单的Cycle属性设置为“当前记录”。
看起来很简单,但你还没有完成。您还必须在父表单的 SubForm_Exit 事件中将 Manufacturer.RowSource 重置为所有制造商,以防用户转到制造商组合框但未进行选择并单击父表单上的某处。代码示例(父形式):
Private Sub sFrmEquip_Exit(取消为整数)
Me.sFrmEquip.Controls("Manufacturer").RowSource = "SELECT MfgrID, MfgrName FROM tblManufacturers ORDER BY MfgrName"
结束子
还有一块不干净。当您单击制造商并在数据表网格中有多行时,当您更改当前行中的制造商时,其他行中的制造商字段将变为空白(组合框下方的数据仍然完好无损)。离开此字段后,其他制造商字段中的文本将重新出现。
【讨论】:
【参考方案7】:这似乎运作良好。 CBOsfrmTouchpoint8 是一个组合框,缩短为下拉方块。 CBOsfrmTouchpoint14 是一个构成其余空间的文本框。 永不言败:
Private Sub CBOsfrmTouchpoint8_Enter()
If Me.CBOsfrmTouchpoint8.Tag = "Yes" Then
CBOsfrmTouchpoint14.SetFocus
Me.CBOsfrmTouchpoint8.Tag = "No"
Exit Sub
End If
Me.CBOsfrmTouchpoint8.Tag = "No"
Me.CBOsfrmTouchpoint8.RowSource = "XXX"
Me.CBOsfrmTouchpoint8.Requery
Me.CBOsfrmTouchpoint8.SetFocus
End Sub
Private Sub CBOsfrmTouchpoint8_GotFocus()
Me.CBOsfrmTouchpoint14.Width = 0
Me.CBOsfrmTouchpoint8.Width = 3420
Me.CBOsfrmTouchpoint8.Left = 8580
Me.CBOsfrmTouchpoint8.Dropdown
End Sub
Private Sub CBOsfrmTouchpoint8_LostFocus()
Me.CBOsfrmTouchpoint8.RowSource = "XXX"
Me.CBOsfrmTouchpoint8.Requery
End Sub
Private Sub CBOsfrmTouchpoint8_Exit(Cancel As Integer)
Me.CBOsfrmTouchpoint14.Width = 3180
Me.CBOsfrmTouchpoint8.Width = 240
Me.CBOsfrmTouchpoint8.Left = 11760
Me.CBOsfrmTouchpoint8.Tag = "Yes"
End Sub
【讨论】:
【参考方案8】:如果您关闭“列表限制”选项,并在更新前进行一些验证以确认用户可能输入的内容与您提供给他们的列表中的内容相匹配,该怎么办?
【讨论】:
【参考方案9】:更好...
将组合框控制源设置为查询中将存储组合框值的列。
【讨论】:
【参考方案10】:对我来说,我认为最好和最简单的方法是创建一个临时表,其中包含所有绑定字段以及一个是/否字段的额外字段。
然后您将使用此表作为连续的数据源。您可以使用 onLoad 将您想要的数据填充到临时表中。
我认为之后循环选择很容易,只需一个小循环即可从临时表中读取是/否字段。
希望对你有帮助
【讨论】:
【参考方案11】:使用OnEnter
事件填充组合框,不要使用固定的rowsource
。
【讨论】:
【参考方案12】:我刚刚做过类似的事情。我的解决方案是使用绑定到查询的固定行源。查询的WHERE
子句引用表单的控件,即Client=Forms!frmMain!ClientTextBox
。仅此一项就会用第一行的数据填充组合框。然后诀窍是设置一个'On Enter
'事件,它只是对组合框进行重新查询,例如ComboBox1.Requery
,这将单独重新查询该组合框,并且只会拖入与该记录行相关的数据。
希望这对你也有用!
【讨论】:
【参考方案13】:免责声明:我非常讨厌 Access。
不要使用连续形式。他们是你想要完成的事情的红鲱鱼。连续形式是用不同的数据一遍又一遍地重复的相同形式。它已经是 Access 正常操作模式的一个组成部分,因为您不能多次打开同一个表单。您看到的行为是 Access 中的“设计”。这些 ComboBox 控件中的每一个实际上都是同一个控件。你不能影响一个人而不影响其他人。
基本上,您在这里所做的事情是碰到了 Access 不再适合您的项目的区域(但不能放弃,因为它已经代表了大量的工作)。
这里似乎最有可能的做法是很好地伪造它。对数据运行查询,然后根据结果以编程方式创建表单元素。这是一项相当大量的工作,因为您将自己复制大量 Access 的数据处理功能。
回复编辑: 但事实上,连续形式无法完成您想要的。这就是为什么我建议伪造你自己的连续形式,因为连续形式在它们可以做的事情上有真正的限制。不要太拘泥于某个特定的实现,以至于当它停止工作时你就放不下它。
【讨论】:
以上是关于Access中连续形式的组合框的自定义行源的主要内容,如果未能解决你的问题,请参考以下文章