☛ 向窗體中添加未綁定組合框以查找數據

在查看 Access 窗體時,經常需要逐頁瀏覽成百上千條記錄以查找想要使用得記錄或記錄集。你可以告訴用戶如何使用 Access 的 ” 查找 ” 功能,執行那些操作以查看其他記錄等,但這有悖於爲應用程序編程的目的。如果構建應用程序,則希望用戶可以更加輕鬆高效地使用你的系統,而不需要教他們如何使用內置到 Access 中的工具。

下圖顯示了一個基於 frmProducts 頂部增加了一個控件的窗體,這個控件是一個未綁定到窗體中的任何數據的組合框。該未綁定組合框用於直接在 tblProducts 中查找記錄,然後使用一些代碼在窗體中顯示該記錄。

該組合框的設計如下圖所示。請注意,” 控件來源 ” 屬性爲空。這表示該組合框未綁定到表中的任何字段,僅由窗體使用,而不更改基礎數據庫中的數據。

該組合框包含兩個查詢選擇的列 ( 如下圖所示 )。第一列 LongDescription 用於連接 tblProducts 表中的 ModelYear 和 Description。第二列是 tblProducts 表中的 ProductID 字段。ProductID 列作爲該組合框的綁定列,其值是在該組合框中選擇一行時該組合框返回的值。第二列的寬度爲 0,會導致在下拉該組合框列表時隱藏該列。

☛ 使用 FindRecord 方法

在 frmProductsExample1 中的快速搜索組合框,其工作方式是從 cboQuickSearch 選擇一種產品後激發 AfterUpdate 事件。AfterUpdate 事件過程中的代碼將對窗體執行搜索,窗體將立即顯示選定的記錄。代碼如下:

Private Sub cboQuickSearch_AfterUpdate()
  
  If Not IsNull(Me.cboQuickSearch.Value) Then
    Me.txtProductID.SetFocus
    DoCmd.FindRecord Me.cboQuickSearch.Value
  End If

End Sub

FindRecord 方法可在窗體的綁定記錄集中查找一條記錄。這等效於使用功能區上的雙筒望遠鏡在數據表中查找記錄。

上面的代碼第一行爲將行檢查以確保 cboQuickSearch 包含值 ( 不爲空 )。如果 cboQuickSearch 爲空,程序流向 End If 語句,不會進行任何搜索。如果 cboQuickSearch 具有值,將執行 If 塊中的代碼,首先是下面的語句:

Me.txtProductID.SetFocus

該語句會將光標移至 txtProductID 控件。就如同需要手動將光標移動到數據表中的一列以便使用功能區上的 ” 查找 ” 圖標一樣,必須將光標放在想要用作搜索目標的綁定控件中。在該範例中,你將光標移到包含 ProductID 值的控件,因爲搜索將在窗體的綁定記錄集中查找特定的 ProductID。

If 塊中的下一個語句如下:

DoCmd.FindRecord Me.cboQuickSearch.Value

在該語句中,FindRecord 方法使用組合框的值 ( 即選定項目的 ProductID ) 以搜索選定產品的記錄。Access 會將 cboQuickSearch 中的值與綁定到窗體的記錄集中的 ProductID 進行匹配。

FindRecord 方法找到的第一個值由一系列參數確定,包括大小寫是否匹配以及搜索是向前還是向後。在代碼窗口中輸入 DoCmd.FindRecord 並按空格鍵可以查看所有可以用選項。FindRecord 方法一次僅查找一條記錄,同時允許查看其他所有記錄。

☛ 使用書籤 Bookmark

當想要用於查找記錄的控件顯示在窗體上時,FindRecord 方法是一種非常好的搜索方式。此外,如果要搜索的值是單個值,也可以使用該方法。書籤是另一種查找記錄的方式。代碼如下所示:

Private Sub cboQuickSearch_AfterUpdate()
  
  Dim rsClone As DAO.Recordset
  Dim sCriteria As String
  
  Const sSEARCHFLD As String = "[ProductID]"
  
  If Not IsNull(Me.cboQuickSearch.Value) Then

    Set rsClone = Me.RecordsetClone
    
    ' Build the criteria:
    sCriteria = sSEARCHFLD & " = " & Me.cboQuickSearch.Value
    
    ' Perform the search:
    rsClone.FindFirst sCriteria
    
    If Not rsClone.NoMatch Then
        'Synchronize the form's bookmark
        'to the recordset's record:
        Me.Bookmark = rsClone.Bookmark
    End If
    
    rsClone.Close
    Set rsClone = Nothing
    
  End If
  
End Sub

上面代碼中的前幾行如下:

Dim rsClone As DAO.Recordset
Dim sCriteria As String

Const sSEARCHFLD As String = "[ProductID]"

If Not IsNull(Me.cboQuickSearch.Value) Then

  Set rsClone = Me.RecordsetClone

前三行聲明一個名爲 rsClone 的記錄集、一個名爲 sCriteria 的字符串及一個名爲 sSEARCHFLD 的常量,該常量設置爲要搜索的字段的名稱。這些對象稍後將在代碼中使用。緊接着,過程將檢查 cboQuickSearch 是否具有值,也就是用戶是否在組合框選擇了某些內容。下一行將記錄集設置爲窗體綁定記錄集的副本 ( RecordsetClone )。

RecordsetClone 與它的名稱完全相符,即在搜索記錄時可以使用窗體記錄集的內存中克隆副本。如果改爲使用窗體的綁定記錄集,搜索會將當前記錄移離窗體中顯示記錄。如果未在窗體的綁定記錄集中找到搜索目標,窗體最終將位於綁定記錄集中的最後一條記錄,這肯定會使用戶產生混淆。

Recordset 對象的 FindFirst 方法需要一個包含條件的搜索字符串以在記錄集中進行查找 ( 沒錯,實際上你是要求 RecordsetClone 基於特定條件在自身中搜索記錄 )。

可以根據需要使用任意複雜的條件字符串。以下語句將連接 [ProductID] ( 我們的常量 ),一個等號以及 cboQuickSearch 的值:

sCriteria = sSEARCHFLD & " = " & Me.cboQuickSearch.Value

假設 cboQuickSearch 的值爲 17,那麼 sCriteria 將爲 [ProductID] = 17。

注意:

之所以可以單獨使用條件字符串,是因爲 ProductID 是一個數字字段,如果是本文字段,則需要在值兩側加上引號,如下所示:

sCriteria = sSEARCHFLD & " = '" & Me.cboQuickSearch.Value & "'"

此時,條件實際上是 [ProductID] = ’17’。

在該範例中,我們針對條件字符串具有很多控制,因爲我們使用的是組合框的值,在其他情況下,我們可以從本文框中獲取條件字符串的組成部分,而用戶幾乎可在該本文框中輸入任何所需要的內容。例如,如果文本框中包含一個在條件字符串中使用的單引號,那麼我們將遇到一種稱爲 ” 嵌入引號 ” 的情況 ( 引用字符串內的引號 )。

幸運的是,嵌入引號非常容易避免。如果需要在引用字符串中使用引號,只需使用兩個引號。例如,如果搜索名稱 O’Mally,代碼應該如下所示:

sCriteria = "[LastName] = 'O''Mally'"

請注意在處理條件字符串時將轉換爲一個引號的 O’Mally 中的兩個引號。要通過文本框實現這一目標,可使用 Replace 函數將一個引號替換爲兩個引號。

sCriteria = "[LastName] = " & _
Replace(Me.txtLastName, String(1, "'"), _
String(2, "'"))

提示:

有時,在代碼中創建條件是一個比較複雜的過程,目標是構建一個可以複製到查詢 SQL 窗口並按原樣運行的字符串。通常情況下,創建條件字符串最好的方式是構建查詢,切換到 SQL 視圖,並將 SQL 語句複製到 VBA 代碼窗口中,將代碼的 WHERE 子句拆分爲字段名稱和控件值,根據需要在字符串和日期值兩側插入連接運算符和分隔符。

 

條件字符串完成後,使用記錄集的 FindFirst 方法在 RecordsetClone 中搜索記錄。下面的代碼行使用記錄集的 FindFirst 方法,以參數形式傳遞條件字符串:

rsClone.FindFirst sCriteria

注意:

你不必創建 sCriteria 變量,然後將條件字符串設置爲該變量,可簡單地將條件放在 rsClone.FindFirst 方法的後面,如下所示:

rsClone.FindFirst "ProductID = " & Me.cboQuickSearch.Value

但是,當具有複雜條件時,通過使用條件字符串的命令單獨創建條件可能會更容易一些,這樣可以在查詢編輯器中單獨調試該字符串。

使用接下來的幾行確定是否應該移動窗體的記錄指針。請注意,下面的代碼塊中引用的 Bookmark 屬性。書籤是一個固定指針,指向記錄集的一條記錄。FindFirst 方法會將記錄集的書籤放在找到的記錄上。

If Not rsClone.NoMatch Then
   Me.Bookmark = rsClone.Bookmark
End If

如果未找到任何記錄,則記錄集的 NoMatch 屬性爲 True。由於你希望在找到記錄的情況下設置書籤,因此需要相當於雙重否定的計算機語言。從本質上說,意思就是如果 ” 不是找不到記錄 “,則書籤是有效的。

如果找到匹配的記錄,窗體的書籤 ( Me.Bookmark ) 將設置爲找到的記錄集的書籤 ( rsClone.Bookmark ),並且窗體會將自身重定位到帶有書籤的記錄。該操作不會篩選記錄,而只是將窗體的書籤放到匹配條件的第一條記錄上。其他所有記錄在窗體中仍然可見。

最後幾行代碼只是關閉記錄集並將其從內存中刪除。

注意:

可根據需要設置複雜條件,甚至可以涉及多個不同數據類型的字段。請記住,字符串必須通過單引號進行分隔 ( 不是雙引號,因爲雙引號用於括住整個字符串 ),日期通過 # 號進行分隔,而數字值不需要分隔。

使用 FindFirst 或 Bookmark 方法要好於使用 FindRecord,因爲它允許使用更復雜的條件,並且不要求被搜索的控件必須可見。你不必將光標預先定位到某個控件上即可使用記錄集的 FindFirst 方法。

這裏說明一下,通過窗體的 RecordsetClone 屬性創建的記錄集是 DAO 類型記錄集。只有 DAO 記錄集支持 FindFirst、FindLast 和 FindNext、FindPrevious 方法。

Access 範例:Access 2016 VBA 代碼編寫範例