コンボボックスがドロップダウンされているか判断する方法
-
解説
AccessのコントロールはVBやVC++など他の言語と違いウィンドウハンドルがありません。
これはリソースの消費を防ぐためフォーカスがある場合のみウィンドウとして扱い、それ以外はただの画像として表示する技術を使用しているためです。(予想)コンボボックスはテキストボックスとリストボックスの2つのウィンドウで構成されています。
これはAccessでも例外ではありません。
ただし、Accessでは前述したとおりフォーカスを受け取るまでコントロールはウィンドウとして扱わないようになっています。コンボボックスがドロップダウンされているか判断するには、リストボックスが表示されているかされていないかで判断できます。
Accessでのコンボボックスのリスト部はODComboというウィンドウクラス名で存在し実際のリスト部はその子ウィンドウになっています。
上記のことからODComboクラスのウィンドウを検索し、その子ウィンドウが表示されている状態であればコンボボックスが開いている状態と判断できます。コンボボックス自体の判定はこれで可能ですがコンボボックスと親ウィンドウの関係を判断する方法が今のところ見つかりません。
とりあえず2つの方法を考えましたが両者ともに欠点があります。
・指定した親のウィンドウハンドルとコンボボックスの親のウィンドウハンドルが一致する場合
・指定した親のウィンドウとコンボボックスの領域が重なるものを親と判断する場合
前者はポップアップフォームになっていない場合コンボボックスの親がAccessのウィンドウになってしまいます。
後者はフォームが重なっている場合でフォーム同士が重なっている場所で、コンボボックスが開かれた場合どちらのコンボボックスかわからなくなります。
しかし、同時に複数のコンボボックスを開くことは物理的に不可能なので問題ないと思います。また、どのコンボボックスがドロップダウンされているかを判定するのはドロップダウンされているウィンドウの座標で判断するしかありません。
-
サンプル
標準モジュール
<親ウィンドウの判定方法:指定したウィンドウハンドルと一致する場合>
Option Compare Database Option Explicit Public Type Type_EnumWindowParameter WindowHandle As Long ComboBoxWindowHandle As Long End Type Private Const GW_OWNER As Long = 4 Private Const GW_CHILD As Long = 5 Private Declare Function GetWindow Lib "user32" _ (ByVal hwnd As Long, _ ByVal wCmd As Long) As Long Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _ (ByVal hwnd As Long, _ ByVal lpClassName As String, _ ByVal nMaxCount As Long) As Long Public Function EnumWindowProc(ByVal WindowHandle As Long, _ ByRef lParam As Type_EnumWindowParameter) As Long Dim Buffer As String Buffer = Space(1024) Call GetClassName(WindowHandle, Buffer, 1024) EnumWindowProc = True If Trim$(Buffer) <> "ODCombo" Then Exit Function End If If GetWindow(WindowHandle, GW_OWNER) <> lParam.WindowHandle Then Exit Function End If lParam.ComboBoxWindowHandle = GetWindow(WindowHandle, GW_CHILD) EnumWindowProc = False End Function
<親ウィンドウの判定方法:コンボボックスウィンドウが指定したウィンドウと重なっている場合>
Option Compare Database Option Explicit Public Type Type_EnumWindowParameter WindowHandle As Long ComboBoxWindowHandle As Long End Type Private Type Type_RECT Left As Long Top As Long Right As Long Bottom As Long End Type Private Const GW_OWNER As Long = 4 Private Const GW_CHILD As Long = 5 Private Declare Function GetWindow Lib "user32" _ (ByVal hwnd As Long, _ ByVal wCmd As Long) As Long Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _ (ByVal hwnd As Long, _ ByVal lpClassName As String, _ ByVal nMaxCount As Long) As Long Private Declare Function GetWindowRect Lib "user32" _ (ByVal hwnd As Long, _ ByRef lpRect As Type_RECT) As Long Private Declare Function IntersectRect Lib "user32" _ (lpDestRect As Type_RECT, _ lpSrc1Rect As Type_RECT, _ lpSrc2Rect As Type_RECT) As Long Public Function EnumWindowProc(ByVal WindowHandle As Long, _ ByRef lParam As Type_EnumWindowParameter) As Long Dim Buffer As String Dim WindowRect As Type_RECT Dim ComboBoxRect As Type_RECT Dim WorkRect As Type_RECT Buffer = Space(1024) Call GetClassName(WindowHandle, Buffer, 1024) EnumWindowProc = True If Trim$(Buffer) <> "ODCombo" Then Exit Function End If Call GetWindowRect(lParam.WindowHandle, WindowRect) Call GetWindowRect(WindowHandle, ComboBoxRect) If IntersectRect(WorkRect, WindowRect, ComboBoxRect) = 0 Then Exit Function End If lParam.ComboBoxWindowHandle = GetWindow(WindowHandle, GW_CHILD) EnumWindowProc = False End Function
フォームのクラスモジュールなど
Private Declare Function EnumWindows Lib "user32" _ (ByVal lpEnumFunc As Long, _ ByRef lParam As Type_EnumWindowParameter) As Long Private Declare Function IsWindowVisible Lib "user32" _ (ByVal hwnd As Long) As Long Private Function IsDropDown() As Boolean Dim Parameter As Type_EnumWindowParameter IsDropDown = False ' 親ウィンドウの判定方法を「指定したウィンドウハンドルと一致する場合」を使用する ' 場合でフォームがポップアップの場合はこちらのパラメータを指定します。 ' 親ウィンドウの判定方法をコンボボックスウィンドウが指定したウィンドウと ' 重なっている場合を使用する場合はこちらのパラメータを指定します。 Parameter.WindowHandle = Me.hwnd ' 親ウィンドウの判定方法を「指定したウィンドウハンドルと一致する場合」を使用する ' 場合でフォームがポップアップではない場合はこちらのパラメータを指定します。 ' Parameter.WindowHandle = Application.hWndAccessApp If EnumWindows(AddressOf EnumWindowProc, Parameter) <> 0 Then Exit Function End If IsDropDown = IsWindowVisible(Parameter.ComboBoxWindowHandle) End Function
使用方法は
If IsDropDown = True Then 'ドロップダウンされている Else 'ドロップダウンされていない End If
と、なります。
-
その他
Access2000以降限定です。
(EnumWindowsの代わりにFindWindowにすることでAccess97で実行することも出来ますが、親子関係を判断するのにちょっと手間がかかります)
管理人はAccess97以外所有していないためサンプルファイルの公開はできません。ご了承ください。このリスト部のウィンドウは1つのフォームに1つしかないようでフォーム内に複数のコンボボックスが存在している場合は使いまわされているようです。
スポンサーリンク
スポンサーリンク
説明がわからないなどありましたらお問い合わせでお知らせください。
ここに掲載された情報を使用したことによって発生した、いかなる損害に対しても
管理者である雅は一切責任を負いません。