【问题标题】:MS Access: Action "onchange" event after a delay?MS Access:延迟后的操作“onchange”事件?
【发布时间】:2021-09-16 23:20:46
【问题描述】:

早上好!

我在 Microsoft Access 中有一个“精美”的搜索功能,当您在搜索字段中键入时,可能的选项列表会缩小。不幸的是,计算机和服务器无法跟上这些快速的数据请求。

目前使用搜索框'onchange'功能中的字段重新查询的命令。我想添加一个延迟,以便它仅在搜索框一秒钟未更改时才运行重新查询。因此,如果有人输入一个 8 个字母的单词,它就不会运行 8 个请求。

我对它的当前想法,我知道肯定有更好的东西,是..

“更改时,将搜索框值设置为 X 并等待 1 秒。1 秒后,如果 X = 搜索框值,则运行重新查询。问题是它会快速重写 X 值并等待' 命令为每个字母浮动。

希望有一种方法可以编写“当字段 X 已更改,但在过去一秒内未更改时”的事件触发器。

谢谢!

根据要求,这是我当前的代码

'Create a string (text) variable
    Dim vSearchString As String
'Populate the string variable with the text entered in the Text Box SearchFor
    vSearchString = SearchFor.Text
'Pass the value contained in the string variable to the hidden text box SrchText,
'that is used as the sear4ch criteria for the Query QRY_SearchAll
    SrchText = vSearchString
'Requery the List Box to show the latest results for the text entered in Text Box SearchFor
    Me.SearchResults.Requery
    Me.SearchResults2.Requery
'Tests for a trailing space and exits the sub routine at this point
'so as to preserve the trailing space, which would be lost if focus was shifted from Text Box SearchFor
    If Len(Me.SrchText) <> 0 And InStr(Len(SrchText), SrchText, " ", vbTextCompare) Then
        'Set the focus on the first item in the list box
            Me.SearchResults = Me.SearchResults.ItemData(1)
            Me.SearchResults.SetFocus
        'Requery the form to refresh the content of any unbound text box that might be feeding off the record source of  the List Box
            DoCmd.Requery
        'Returns the cursor to the the end of the text in Text Box SearchFor,
        'and restores trailing space lost when focus is shifted to the list box
            Me.SearchFor = vSearchString
            Me.SearchFor.SetFocus
            Me.SearchFor.SelStart = Me.SearchFor.SelLength
            Exit Sub
    End If
'Set the focus on the first item in the list box
'    Me.SearchResults = Me.SearchResults.ItemData(1)
    Me.SearchResults.SetFocus    
'Requery the form to refresh the content of any unbound text box that might be feeding off the record source of  the List Box
    DoCmd.Requery
'Returns the cursor to the the end of the text in Text Box SearchFor
    Me.SearchFor.SetFocus
    If Not IsNull(Len(Me.SearchFor)) Then
        Me.SearchFor.SelStart = Len(Me.SearchFor)
    End If

显然这不是我的代码,它来自互联网上的某个地方。它适用于存储在本地的数据库,但一切都转移到我们的 Sharepoint 服务器上,该服务器在发霉的地下室的 386 上运行,由嗜睡沙鼠驱动。

【问题讨论】:

  • 问题是搜索字段可以是 1 到 255 个字符之间的任意位置。我想要的是在更改搜索框并且在过去一秒内未更改时运行重新查询。这样,当您输入一个 8 个字母的单词时,它就不会运行 8 个请求。
  • Access 不允许异步计算,计划任务可以通过表单和触发器完成,但有点 hacky。虽然可以,但我建议您不要这样做。
  • 我的数据库中有很多东西属于“我建议你不要”类别。此特定修复属于“硬件问题的软件解决方案”

标签: vba ms-access


【解决方案1】:

您正在寻找的技术术语是去抖动。

你可以做的是在你的 on change 事件上,跟踪当前的搜索字符串

就伪代码而言。

sub onChange()
   Form.timerinterval = 0
   setSearchString
   form.timerinterval = delay

因此,就解释而言,如果您的 on change 被调用,请禁用计时器。更新您的搜索字符串,然后将计时器重置为在一定时间后触发。该表单应该是一个隐藏表单,其中包含您要执行的代码

【讨论】:

  • @ErikvonAsmuth 虽然 Access 没有应用程序级计时器,但有表单级计时器。您可以设置 TimerInterval,然后在 Form_Timer 事件中执行相同的逻辑。
  • 使用“DoUntil”作为延迟检查怎么样?所以像“在更改时,将值 X 设置为搜索框值并将 DoOnTime 值设置为 Now() 加上 1 秒。直到 DoOnTime 值 = now(),然后如果 X = searchboxvalue 然后运行命令......这很快就会变成意大利面条.
  • 我不会忙着等待。这会消耗 CPU 周期
  • CPU 上的繁忙周期比在服务器上调用多个查询更可取,我很确定这是发霉的地下室中的 386,由嗜睡的仓鼠驱动。
  • @EricYang 我试图理解发布的代码。 “addtosearchstring”是什么意思?
【解决方案2】:

为 on change 事件中的逻辑分配一个快捷键,如 (Ctrl+J),并在输入完搜索关键字后按需调用它。

  1. 删除更改事件。
  2. 创建其他具有 on change 事件逻辑的过程并分配快捷键
  3. 按快捷键获取搜索建议

其他方法

在 Change 事件中添加以下验证,该事件将检查字符串的长度,并且仅当字符串的长度 >=8 时才会触发

Private Sub txtSearch_Change()

    If Len(Nz(txtSearch.Text, 0)) >= 8 Then


    End If

End Sub

【讨论】:

  • 不幸的是,我不是唯一使用此数据库的人,而且随着您键入而缩小的列表的“花哨”是管理的卖点之一。
  • @RobertPatrician fanciness 将付出代价。这种方法会消耗最少的资源,并且在按下快捷键时仍然会得到建议。否则将搜索框更改为组合框。
  • 我会使用If Len(Nz(txtSearch.Text, 0)) &gt;= 4,因为第一次搜索不那么有趣而且更昂贵。 3 或 4 个字符可能是 fancyefficient 之间的良好折衷
【解决方案3】:

由于我几乎不使用 MS Access 表单,所以我有点超出了我的舒适范围,但是你为什么要这么麻烦服务器/数据库呢?根据我的经验,每个查询花费相同的时间,无论是返回 1 条记录还是 100,000 条记录。

因此,即使在用户输入任何内容之前,您为什么不只执行一次查询以返回排序列表。之后,几乎不用花时间使用 VBA 来处理结果并在列表中查找以用户输入的任何内容开头的所有内容(毕竟是排序的)。

除了初始加载之外,数据库本地用户或世界另一端的用户将在您的界面中体验到同样快速的响应。

---------

就像我说的,我没有经常使用 Access Forms,所以这更像是一个严格的 VBA 解决方案。也许有一种更好的方法可以做到这一点,而无需超出有人可以启发我们的“访问表单”框。

您基本上应该在加载表单时或在需要时调用LoadItemList

Public dbConn As ADODB.Connection
Private ItemList As Variant
Private RecordCount As Long

Sub LoadItemList()
Dim SQL As String
Dim RS As New ADODB.Recordset

    SQL = "SELECT T.Name FROM Table T"
    Set RS = dbConn.Execute(SQL)
    If Not RS.EOF Then
        ItemList = RS.GetRows
        RecordCount = UBound(ItemList, 2) - LBound(ItemList, 2) + 1
    End If
End Sub

然后将DoCmd.Requery替换为AddItemtoCombobox SearchResults, SearchFor.Text

Sub AddItemtoCombobox(Control As ComboBox, Filter As String)
Dim Index As Long
    Control.Clear
    If Not IsEmpty(ItemList) Then
        For Index = 0 To RecordCount - 1
            If ItemList(Index) Like Filter Then Control.AddItem ItemList(Index)
        Next
    End If
End Sub

再说一次,也许有更好的方法内置于 Access...

【讨论】:

  • 根据我的经验,在大多数情况下,您的方法是最好的。太棒了!
  • 嗯,这是一个“Like * & searchfield & *”标准,所以如果你搜索“west”,它会带回“Western wear”和“George West”以及“Northwest Industries”但是我不知道不知道如何进行您建议的过滤。现在,查询从数据库中拉回与搜索字段匹配的所有记录,并将它们放入组合框中。我从哪里开始有一种方法,它首先将所有记录加载到组合框中,然后根据搜索字段对其进行过滤?
  • 就像我说的,Access 有点超出我的舒适范围,但我只是将整个 Recordset 保存到一个数组或其他东西中,然后遍历整个列表。对每一项使用 VBA 的Like 语句;如果匹配,则将其添加到组合框中。也许有更好的方法,但我暂时想不到。
【解决方案4】:

您可以简单地使用当前表单的 Timer。不需要单独的表格或任何东西。

Private Sub DoSearch()

    ' Your current code
    ' but you should look into removing as many "Requery" from there as possible!

End Sub

Private Sub SearchFor_Change()

    ' Wait for x Milliseconds until the search is started.
    ' Each new change restarts the timer interval.
    ' Use 1000 (1 s) for slow typists or a really slow server
    ' 200 ms feels right for a normal typist
    Me.TimerInterval = 200

End Sub

Private Sub Form_Timer()

    ' Disable timer (will be enabled by the next SearchFor_Change)
    Me.TimerInterval = 0
    ' Now run the search
    DoSearch

End Sub

注意:您可能需要将一些光标处理代码从DoSearch() 移动到SearchFor_Change(),具体而言:

Me.SearchFor.SelStart = Len(Me.SearchFor)

【讨论】:

    猜你喜欢
    • 2018-11-13
    • 2022-08-17
    • 2017-06-16
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    相关资源
    最近更新 更多