- ホーム
- Other
- Old fashioned form filter
Old fashioned filter of Access form
Access2010では、表形式フォーム(昔は帳票と呼んだ様な..)のフィルターアイコンの動作がExcelのオートフィルターのドロップダウンを押した時の様な動作になってしまいました。
Access2000の時の様な動作をVBAで実現しようとして、出来たのですが、詳細セクションのテキストボックスのイベントの羅列になり面倒なので、
疑似コントロール配列化し、多数ある他のフォームに楽に適用したいと考えました。
詳細セクションの各テキストボックスを包含するクラスを作り、クリックイベントでどの列(フィールド)を選択しているかを取得し、保存します。
各テキストボックスのオブジェクト名はコントロールのコレクションから自動で取得する事で、汎用性を持たせます。
ところが、クリックイベントが発生しない。表形式フォームのためなのか?Control型で受けてTextBox型に代入しているからかなどと思い悩み、
ごく単純なコードまでシュリンクしても動作しない。(ほぼ同じコードでExcelではイベント発動するのに)
Q&Aサイトに質問しようかと思いながら、それでもとキーワードを変えて検索していて、辿り着きました。最初意味を掴みかねたのですが、
その通りを設定すれば良かったのです。クラスモジュールで当該TextBoxを代入したオブジェクトに、Onclickを設定する必要があるのです。
myTextBox.OnClick = "[Event Procedure]"
最終的に、フィルターをかける部分も親クラス化して、フォームモジュール側の記述を最小限で出来る様にしてみました。
表形式フォームのフッターセクション等にテキストボックスを2個設け、片方をフィルター実施用、他方を解除用のボタンとします。
フィルターボタンを押すたびにAND条件でフィルターがかかる様にしてみました。
☆実行元の帳票フォーム(表)フォームモジュール
'オールドファッションフィルターをクラス化
Dim oldFilterCls As oldFashionFilterCls
'初期化ルーチンで親クラス設定
'親クラスに、実行元のフォームを渡す
Private Sub Form_Load()
Set oldFilterCls = New oldFashionFilterCls
Set oldFilterCls.Form = Me
End Sub
'フィルタをかける
Private Sub filterButton_Click()
oldFilterCls.filterOn
End Sub
'Fileterボタン横の解除ボタン
Private Sub resetFilterButton_Click()
oldFilterCls.filterOff
End Sub
☆親クラス oldFashionFilterCls
'===============================================================
' Old fashioned Filter Class
' 旧称帳票フォーム(2010では表フォーム)のフッターセクション等に
' CommandButtonを二個 (フィルター設定、解除)置いて
' Access2000の頃のフィルター動作+重ね掛け機能を実現
' 2013/1/24, 2013/1/28修正
'===============================================================
Dim myForm As Object
'複数条件でのフィルター様にモジュールレベルで保持
Dim filterString As String
'詳細セクションのテキストボックスを引き継ぐクラスモジュールのメモリを確保
Dim myControls() As exControlClass
'選択列 最初非可視ラベルでやっていたが載せ替え
Dim selectedColumn As String
'フォームがセットされているかのフラグ
Dim myFlagFormSet As Boolean
Public Property Get flagFormSet() As Boolean
flagFormSet = myFlagFormSet
End Property
Public Property Set Form(newForm As Object)
Dim myControl As Control
Set myForm = newForm
myFlagFormSet = True
ReDim myControls(0 To 0)
For Each myControl In myForm.Section(0).Controls
If TypeName(myControl) = "TextBox" Then
ReDim Preserve myControls(0 To UBound(myControls) + 1)
Set myControls(UBound(myControls)) = New exControlClass
myControls(UBound(myControls)).setTextBox myControl, UBound(myControls)
Set myControls(UBound(myControls)).parent = Me
End If
Next myControl
End Property
'クラスモジュールから起動して、indexを保持(文字列形式)
Sub controlslClicked(myObj As exControlClass)
selectedColumn = CStr(myObj.index)
End Sub
'フィルタをかける
Public Sub filterOn()
Dim tempfilterString As String
Dim fieldName As String, fieldValue As Variant
If myForm Is Nothing Then
MsgBox "フォームがセットされていません"
Exit Sub
End If
'2013/1/28 テキストボックス以外の要素のある詳細セクションでの不具合対策で子クラスからの取得に変更
fieldValue = myControls(selectedColumn).value
fieldName = myControls(selectedColumn).name
Select Case TypeName(fieldValue)
Case "String"
tempfilterString = fieldName & "='" & fieldValue & "'"
Case "Date"
tempfilterString = fieldName & "=#" & fieldValue & "#"
Case Else
tempfilterString = fieldName & "=" & fieldValue
End Select
If filterString = "" Then
filterString = tempfilterString
Else
filterString = filterString & " AND " & tempfilterString
End If
myForm.filter = filterString
myForm.filterOn = True
End Sub
'Filter解除
Public Sub filterOff()
If myForm Is Nothing Then
MsgBox "フォームがセットされていません"
Exit Sub
End If
myForm.filterOn = False
filterString = ""
End Sub
☆子クラス exControlClass
Private WithEvents myTextBox As TextBox
Private myIndex As Long
Private myParent As Object
Public Sub setTextBox(newTextBox As TextBox, newIndex As Long)
Set myTextBox = newTextBox
'これがミソで、これを入れないとClickイベントがクラスに引き継がれない
myTextBox.OnClick = "[Event Procedure]"
myIndex = newIndex
End Sub
'TabIndexを用いる手もあるが、取りあえず取得順を保持している
Public Property Get index() As Long
index = myIndex
End Property
Private Sub myTextBox_Click()
Call myParent.controlslClicked(Me)
End Sub
Public Property Set parent(newParent As Object)
Set myParent = newParent
End Property
'2013/1/28 テキストボックス以外の要素のある詳細セクションでの不具合対策で追加
Public Property Get name() as String
name = myTextBox.name
End Property
Public Property Get value() as String
value = myTextBox.value
End Property