如何使用VBA将Recordset填充到ComboBox中

8

有一些与在Access表单中使用combobox.recordset属性填充下拉框相关的文献可在expert's exchangeteck republic上获取。

这些控件通常通过控件的“rowsource”属性中的“SELECT *”字符串来填充,引用客户端应用程序中可用的表或查询。当我需要在下拉框中显示服务器端数据时,我会创建一个临时本地表并导入所请求的记录。这很耗时,特别是对于大型表格。

能够使用recordset填充combobox控件将允许用户直接显示来自服务器端的数据。

受前两个示例的启发,我编写了以下代码:

Dim rsPersonne as ADODB.recordset
Set rsPersonne = New ADODB.Recordset

Set rsPersonne.ActiveConnection = connexionActive
rsPersonne.CursorType = adOpenDynamic
rsPersonne.LockType = adLockPessimistic
rsPersonne.CursorLocation = adUseClient

rsPersonne.Open "SELECT id_Personne, nomPersonne FROM Tbl_Personne"

fc().Controls("id_Personne").Recordset = rsPersonne

在哪里:

  • connexionActive:是我与数据库服务器的永久ADO连接
  • fc():是我的当前/活动表单
  • controls("id_Personne"):是要填充公司员工列表的组合框控件
  • Access 2003版本

不幸的是,它不起作用!

在调试模式下,我可以检查记录集是否正确创建,请求的列和数据是否正确关联到组合框控件。不幸的是,当我显示表单时,我仍然得到一个空的组合框,其中没有记录!非常感谢任何帮助。

编辑:

这个记录集属性确实适用于特定的组合框对象,而不是标准控件对象,我几天前发现它时非常惊讶。 我已经尝试使用组合框的回调函数,或者使用组合框的“addItem”方法填充列表。所有这些都很耗时。

6个回答

6

要将接受行源的控件设置为记录集,您需要执行以下操作:

Set recordset = currentDb.OpenRecordset("SELECT * FROM TABLE", dbOpenSnapshot)
Set control.recordset = recordset

可以肯定地使用DAO Recordsets,我没有尝试ADO Recordsets,因为我没有真正使用它们的原因。

使用这种方式完成后,简单的重查将无法刷新数据,您必须重复设置语句。


个人而言,我忘记使用“Set”关键字将记录集分配给我的控件。谢谢! - David Alan Condit

5

如前所述,您必须将RowSourceType设置为“Table/Query”(如果是法语,则为“Table/Requête”)才能在组合框中显示查询结果。

由于在不关闭记录集(rsPersonne)的情况下打开它,导致了内存问题。您应该在关闭/卸载表单时关闭记录集(但再次提醒,因为记录集在函数中声明而不在表单中,所以可能会出现范围问题)。

您还可以尝试使用Access的内置查询创建工具创建和保存查询,并将该查询插入组合框的RowSource中。这样,查询将在Access中得到验证和编译。


我会检查您关于内存问题的建议,并尽快回复您。 - Philippe Grondier

3

我发现了一个诀窍...需要将组合框控件的"rowSourceType"属性设置为"Table/Query"。现在显示已经正常,但是我现在遇到了另一个内存问题。由于我在表单上使用这些ADO记录集,每次浏览表单时,Access的内存使用量都会增加。停止浏览或关闭表单也不会释放内存,导致MS Access不稳定并且经常冻结。如果我无法解决此问题,我将打开一个问题。


不起作用:/ 出现错误91: 没有出现的块。 - Quentin T.
如果你想要建议,你应该提供有问题的代码并且标识出出错的那一行。 - Philippe Grondier
错误描述:https://dev59.com/qHHYa4cB1Zd3GeqPLW1W - Quentin T.
如果您在使用此方法时遇到问题,可以尝试使用AddItem方法,这可能更容易些。您可以通过使用分号将多个列的值进行分隔来指定多个列的值(AddItem仅接受单个字符串)。 - Matt Browne
1
我总是在使用完毕后将Set rs = Nothing。我认为这应该可以防止内存泄漏。 - Alan Fisher
显示剩余2条评论

2

使用Recordset属性的好方法,感谢那个提示!

帕特里克,在你的页面上展示的方法有一个很大的缺点(我也尝试了一下):值列表只能是32 KB,如果超过这个限制,函数就会抛出错误。回调方法的缺点是非常慢,而且对于较长的列表每个条目都需要调用一次,使其无法使用。使用记录集方法非常好。我需要这个方法因为我的SQL字符串比32 KB还要长(对于WHERE ID IN(x,x,x,x,x ...)有很多索引值)。

以下是一个简单的函数,使用此想法将记录集设置为组合框:

' Fills a combobox with the result of a recordset.
'
' Works with any length of recordset results (up to 10000 in ADP)
' Useful if strSQL is longer than 32767 characters
'
' Author: Christian Coppes
' Date: 16.09.2009
'
Public Sub fnADOComboboxSetRS(cmb As ComboBox, strSQL As String)
    Dim rs As ADODB.Recordset
    Dim lngCount As Long

   On Error GoTo fnADOComboboxSetRS_Error

    Set rs = fnADOSelectCommon(strSQL, adLockReadOnly, adOpenForwardOnly)

    If Not rs Is Nothing Then
        If Not (rs.EOF And rs.BOF) Then
            Set cmb.Recordset = rs
            ' enforces the combobox to load completely
            lngCount = cmb.ListCount
        End If
    End If

fnADOComboboxSetRS_Exit:
    If Not rs Is Nothing Then
        If rs.State = adStateOpen Then rs.Close
        Set rs = Nothing
    End If
    Exit Sub

fnADOComboboxSetRS_Error:
    Select Case Err
        Case Else
            fnErr "modODBC->fnADOComboboxSetRS", True
            Resume fnADOComboboxSetRS_Exit
    End Select
End Sub

(fnADOSelectCommon函数打开一个ADO记录集并返回它。fnErr函数如果有错误则显示一个消息框。)

由于此函数关闭了已打开的记录集,因此内存应该不会出现问题。我进行了测试,并没有看到在关闭带有组合框的窗体后未释放的内存增加。

在表单的卸载事件中,您还可以使用“Set rs=Me.Comboboxname.Recordset”,然后关闭它。这在内存方面可能不是必要的,但如果与后端数据库服务器一起使用,则最好释放打开的连接。

祝好,

Christian


当然,我的方法是有限的。我创建它是因为我必须从一个非常慢的查询(大约1分钟)中填充列表。使用字符串技巧可以在不重新运行长查询的情况下快速重新排序列表中的任何列。 - iDevlop

0

组合框控件没有记录集属性。它确实有一个RowSource属性,但Access期望在其中提供一个SQL字符串。

您可以将RowSourceType更改为用户定义的“回调”函数的名称。通过将光标放在RowSourceType上并按F1键,Access帮助将为您提供更多信息,包括示例代码。当我想要向用户提供可用报告、驱动器字母或其他不可通过SQL查询获得的数据列表时,我使用此类型的函数。

关于您第三段所说的直接从服务器端使用数据,我不理解。或者说,我不明白使用标准查询存在什么问题。


谢谢Tony。这个记录集属性确实适用于特定的组合框对象,而不是标准控件对象。我也在类似于你的情况下使用这个回调函数。我的问题是找到一种方法,在客户端使用来自服务器端的数据填充组合框。到目前为止,我一直在创建本地临时表来完成这个任务,但这真的很耗时间。我希望使用记录集会更有效率。 - Philippe Grondier
你为什么认为将记录集分配给组合框会比让Access/Jet管理SQL字符串的数据检索更有效率?你是指你正在使用断开的记录集吗?我无法想象为什么有人会需要你所要求的东西——对我来说毫无意义。 - David-W-Fenton
是的,ADO记录集已断开连接。 - Philippe Grondier
@David-W-Fenton 如果源记录集是ADO,则将其分配给组合框的RecordSource属性看起来很吸引人,这样您就不必将内容复制到ValueList或Table中。特别是因为MSDN文档中对RecordSource的说明显示您可以将ADO或DAO记录集分配给此属性。但它没有说只能在表单上这样做。如果在组合框上这样做,可能会非常不稳定,即使它能工作,我发现一旦出现工作情况,Windows更新后会开始抛出错误。 - Caltor

0
在MS Access中,这没问题,但在VB中,您可以使用类似于以下内容的adodc(Jet 4.0):
Private sub Form1_Load()
   with Adodc1
     .commandtype = adcmdtext
     .recordsource = "Select * from courses"
     .refresh

     while not .recordset.eof
           combo1.additem = .recordset.coursecode
           .recordset.movenext
     wend
   end with
End Sub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接