儘管使用 FindRecord 或 FindFirst 方法使你可以快速查找滿足所需條件的記錄,但仍會顯示錶或查詢記錄集中的所有記錄,並且不一定將所有記錄保存在一起。篩選窗體使你可以僅查看所需的記錄或記錄集,同時隱藏所有不匹配的記錄。

如果記錄集很大,而你只希望查看與需求匹配的記錄子集,那麼篩選器是很好的選擇。

☛ 使用代碼

下面的代碼顯示了針對窗體的記錄集創建和應用篩選器所需的兩行代碼。每個窗體都包含一個 Filter 屬性,用於指定如何篩選綁定記錄。默認情況下,Filter 屬性爲空,並且窗體將顯示基礎記錄集中的所有記錄。

Private Sub cboQuickSearch_AfterUpdate()

   Me.Filter = "ProductID = " & Me.cboQuickSearch.Value
   Me.FilterOn = True
   
End Sub


Private Sub cmdClearFilter_Click()
  
  Me.Filter = vbNullString
  Me.FilterOn = False
  'ResetFilter
  Me.cboQuickSearch.Value = Null
      
End Sub

第一行代码设置窗体的 Filter 属性:

Me.Filter = "ProductID = " & Me.cboQuickSearch.Value

注意,該字符串與用作傳遞到記錄集的 FindFirst 屬性條件的字符串完全相同。

第二行代碼 ( Me.Filter = True ) 啓用篩選器。你可將所需的所有條件放置到一個篩選器屬性中,但是,除非你顯式地將 FilterOn 屬性設置爲 True,否則篩選器永遠也不會應用於窗體的記錄集。篩選器將隱藏與條件不符的所有記錄,僅顯示滿足篩選器值得記錄。

Me.FilterOn = True

啓用篩選器後,最好提供一種禁用篩選器的方式。在上圖的組合框旁邊有一個小按鈕 ( cmdClearFilter )。該按鈕可禁用篩選器,並將窗體的 Filter 屬性設置爲空字符串 ( vbNullString )。下面爲該按鈕按下後的代碼運行過程:

Private Sub cmdClearFilter_Click()
  
  Me.Filter = vbNullString
  Me.FilterOn = False
  'ResetFilter
  Me.cboQuickSearch.Value = Null
      
End Sub

警告:

如果創建窗體篩選器,然後保存設置了篩選器的窗體設置,該篩選器將與窗體一起保存。下次打開該窗體時,保存的篩選器將處於活動狀態。當窗體關閉時,將窗體的 Filter 屬性設置爲空字符串是一種非常好的做法。下面的代碼使用窗體的 Close 事件過程來清除篩選器:

Private Sub Form_Close()
  
  Me.Filter = vbNullString
  Me.FilterOn = False
  
End Sub

除了清除組合框的行以外,該代碼與 cmdClearFilter_Click 中的代碼相同。爲獲得更整潔的基本代碼,建議將重複代碼移動到其自己的過程中。下面顯示了這兩個事件過程以及具有重複代碼的新過程:

Private Sub cmdClearFilter_Click()
  
  Me.Filter = vbNullString
  Me.FilterOn = False
  'ResetFilter
  Me.cboQuickSearch.Value = Null
      
End Sub


Private Sub Form_Close()
  
  ResetFilter
  
End Sub

Private Sub ResetFilter()
  
  Me.Filter = vbNullString
  Me.FilterOn = False
  
End Sub

这两个事件过程都调用 ResetFilter,而不是使用重复代码。

☛ 使用查詢

你可能希望使用一個窗體控制另一個窗體。或者,你可能希望記錄集根據用戶輸入的即席條件顯示選定的數據。例如,每次運行報表時,都會顯示一個對話框,然後用戶輸入一組日期或者選擇產品或客戶。執行這項任務的一種方式是使用參數查詢。

⑴ 創建參數查詢

參數查詢指的是包含基於對變量、函數或窗體控件的引用的條件的查詢。通常情況下,可在條件輸入區域中輸入諸如 SMITH、26 或 6/15/12 之類的值。也可以輸入提示,例如 [Enter the Last Name],或者對窗體上控件的引用,例如 Forms!frmProducts![cboQuickFind]。

創建參數查詢最簡單的方法是創建一個選擇查詢,指定查詢條件,並運行該查詢以確保其可以正常工作。然後將條件更改爲以下內容:

Like [<some prompt>] & "*"

或者

Like "*" & [<some prompt>] & "*"

其中,<some prompt> 是你想要向用户提出的问题。下图显示了一个参数查询,当运行查询时提示用户输入产品类别。

提示:

可在任何查詢或 SQL 字符串中將通配符 * ( 該位置後可以是任何字符 ) 和 ? ( 該位置代表一個字符 ) 與 Like 運算符結合使用。

向參數中添加 * 號的結果是,如果用戶不輸入參數值,那麼條件將求解爲 ” Like *”,而查詢將返回除 Null 外的所有記錄。如果用戶未能提供產品類別,將 * 號放在條件表達式以外將導致不返回任何記錄。

提示:

如果想添加更復雜的參數,例如日期範圍,請在日期字段中使用諸如 Between [Enter the Start Date] and [Enter the End Date] 之類的表達式作爲條件,這會顯示兩個單獨的參數對話框,然後相應地篩選日期值。

☛ 創建交互式篩選對話框

參數查詢的問題在於,它們只適合於簡單參數。用戶必須精確瞭解要輸入到參數對話框的內容,如果他們輸入的參數有誤,則不會看到預期的結果。此外,使用參數查詢來輸入複雜條件相當困難。

更好的方法是創建一個簡單窗體,在窗體上放置控件,並以參數形式從查詢引用這些控件。換句話說,查詢使用窗體的控件獲取其參數值。對於用戶來說,這是一個巨大的優勢,因爲控件可以呈現可接受參數值的列表或下拉菜單,從而幫助用戶選擇條件。此外,可以向每個控件的 AfterUpdate 事件添加代碼來驗證用戶的輸入,以確保查詢可以真正運行。諸如組合框或列表框之類的控件的內容可以是動態的,包含來自基礎表的實際值。這意味着條件控件可能僅包含下達了訂單的客戶的名稱,或者當時實際位於數據庫中的產品類別。

下圖顯示了設計視圖中的 frmFilterProducts。cboCategory 中填充了來自 qryCategories 的數據,其中按照字母順序對 tblCategories 表中的記錄進行排序。

cboCategory 的默認值屬性設置爲 “Cars”,因爲這是 Products 窗體最常用的條件。在該示例中,” 限於列表 ” 設置爲 ” 是 “,因爲我們希望強制用戶僅從實際位於 tblCategories 表的類別中進行選擇。

上圖顯示了 qryProducts_FromParameter。該查詢將基於從 frmFilterProducts 上的 cboCategory 中檢索的類別選擇 tblProducts 中的所有字段。請注意 Category 列中的條件表達式,如下所示:

= [Forms]![frmFilterProducts]![cboCategory]

當查詢運行時,它將自動從 cboCategory 檢索條件值。該組合框將返回 Cars,除非用戶已經選擇了其他類別。

在正常的操作中,用戶將從 frmFilterProducts 選擇一個產品類別,並單擊 OK 按鈕。該按鈕背後的代碼將打開 frmProductExample4,該窗體綁定到 qryProducts_FromParameter。qryProducts_FromParameter 中 Category 字段的條件將在 frmFilterProducts 上的 cboCategory 中查找選定的值,並將打開 frmProductsExample4,其中僅加載選定的產品類別。

對於處理這種緊密集成的數據庫對象 ( 在範例中爲 frmFilterProducts、qryProducts_FromParameter 和 frmProductsExample4 ) 的開發人員來說,其所面臨的唯一問題在於,並不能非常明顯地看出這些對象協同工作。刪除或修改其中的任何對象可能會打破工作流或者爲用戶帶來問題。

你可以選用某種命名約定,即在名稱中指示兩個窗體和查詢之間的關係,例如爲每一項提供相同的名稱,但使用不同的前綴。或者,也可在 ” 導航 ” 窗格中使用自定義組,並將對象添加到單個組中。作爲最初的設計人員和開發人員,很多情況下對你顯而易見的一些事情對其他人來說可能不是非常清楚,因此,利用簡單的方法幫助記錄你的應用程序非常有益。

警告:

在 frmFilterProducts 未打開的情況下運行 qryProduct_FromParameter 會導致查詢提示用戶輸入值。當 frmFilterProducts 未打開時,Access 不能指出條件 [Form]![frmFilterProducts]![cboCategory] 表示什麼,因爲沒有加載名爲 frmFilterProducts 的窗體。這種情況下,Access 會假定參數是一個提示,並顯示一個輸入框。

☛ 將對話框鏈接到另一個窗體

frmFilterProducts 對話框並不僅僅是創建一個可以從查詢引用的值。它還包含用於打開 frmProductsExample4 的代碼。代碼如下所示:

Private Sub cmdCancel_Click()

  DoCmd.Close acForm, Me.Name
  
End Sub

Private Sub cmdOK_Click()
  
  Const sFORM As String = "frmProductsExample4"
  
  DoCmd.OpenForm sFORM
  
  With Forms(sFORM)
    .SetFocus
    .Requery
  End With

End Sub

cmdOK_Click 事件過程代碼將打開 frmProductsExample4,在其上設置焦點,然後重新查詢窗體以確保在窗體上使用最新選擇的內容。必須使用 SetFocus 方法將焦點移動到打開的窗體。Requery 方法並不是嚴格必需的,因爲窗體會在其第一次打開時自動重新查詢記錄源。但是,如果窗體已經打開,例如,第二次使用該對話框來搜索另一條記錄,Requery 方法可確保窗體顯示新的數據。

儘管未在 frmFilterProducts 中實施,但 cmdOK_Click 事件過程也可以包含一個 DoCmd.Close 語句,用於在打開 frmProductsExamples4 後關閉對話框。或者,也可以選擇使對話框保持打開狀態,以便用戶選擇另一個產品類別進行查看。

使用 With 關鍵字

使用 With 關鍵字時無須顯式 ( 也就是直接 ) 引用窗體上的控件,例如 Forms!frmProductsExample4.SetFocus,從而節省執行時間。該語法要求 Access 按字母順序搜索數據庫容器中的窗體列表。如果有 500 個窗體 ( 某些大型系統會具有這麼多的窗體,有時甚至會更多 ),而要搜索的窗體名稱以 z 開頭,那麼該搜索將持續相當長的時間。由於存在多個窗體的引用,因此,需要多次執行該過程。With 命令可設置一個指向該窗體的內部指針,因此,對該窗體的控件、屬性或方法 ( 例如 Requery 或 SetFocus ) 的所有後續引用會快很多。

當使用 With 關鍵字並引用窗體名稱時,只需使用句點 ( . ) 或感嘆號 ( ! ) 引用控件、屬性或方法,比如 Forms!ForName 屬於第一種。

對於每個 With,必須具有與之對應的 End With。

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