- ベストアンサー
ComboBoxについておしえてください
↓・↑とクリックを区別したいのですがどうすればよいのか 教えてください。 ↑をおすとKeyDownにいきClickにいきます。 ↑をおしたときにClickにいかないようにすることはできませんか? よろしくおねがいします。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
サンプルを作ってみました。 必要なものは フォーム1 コンボボックス1 標準モジュール です。 処理を説明します。 サブクラス化という処理をしています。 VBにはクリックやボタンダウンなどのイベントがありますが、全てWIndowsが送ってくる定数(メッセージ)を読み取り、その値によってイベントの内容が決まります。このプログラムはコンボボックスにくるWINDOWSからのメッセージをcomboProc関数にて監視し(これがサブクラス化)、カーソルのイベントだけコンボボックスのリスト部分が非表示のときには、メッセージをWINDOWSに返さないようにしています。もしリスト部分が表示されていても、WM_COMMANDという決定というメッセージを返さないようにしています。 サブクラス化の最中に強制終了をすると、VBが落ちます。必ず普通にフォームを閉じて終了しましょう。 常にこの関数が動いている状態なので、プログラム作成最終段階での組み込みをお奨めします。それまでは、[サブクラス化の開始][サブクラス化の終了]部分をコメントにしておくだけで、このプログラムは動きませんので安心してください。 -----フォーム1(ここから)----- Private Sub Form_Load() With Me 'ダミーのデータ With .Combo1 .AddItem 1 .AddItem 2 .AddItem 3 .AddItem 4 End With 'サブクラス化の開始 pLngProc = SetWindowLong(.Combo1.hwnd, GWL_WNDPROC, AddressOf comboProc) End With End Sub Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) With Me 'サブクラス化の終了 Call SetWindowLong(.Combo1.hwnd, GWL_WNDPROC, pLngProc) End With End Sub -----フォーム1(ここまで)----- -----標準モジュール(ここから)----- Option Explicit Public Const GWL_WNDPROC As Long = (-4) Private Const WM_COMMAND = &H111 'メニューが選択されたあるいはコントロールにイベントが発生した Private Const WM_KEYDOWN = &H100 'キーボードのキーが押された Private Const WM_KEYUP = &H101 'キーが解放された Private Const CB_GETDROPPEDSTATE = &H157 'コンボボックスでリストボックス部が開いているかどうか調べる Private Const CB_SHOWDROPDOWN = &H14F 'コンボボックスでドロップダウンリストを表示・非表示 Private Const KEY_UP As Byte = &H1 Private Const KEY_DOWN As Byte = &H2 Public Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long 'プロセス Public pLngProc As Long 'カーソル↑←を押されたとき、1バイト目にフラグを立てる 'カーソル↓→を押されたとき、2バイト目にフラグを立てる Private bytKeyFlg As Byte Public Function comboProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Select Case uMsg 'キーダウン Case WM_KEYDOWN 'wParamにはキーコードが入る Select Case wParam 'カーソル↑← Case vbKeyUp, vbKeyLeft '1バイト目にフラグを立てる bytKeyFlg = bytKeyFlg Or KEY_UP 'カーソル↓→ Case vbKeyDown, vbKeyRight '2バイト目にフラグを立てる bytKeyFlg = bytKeyFlg Or KEY_DOWN 'その他のキー Case Else '通常処理でメッセージを返す GoTo PGMEND End Select 'コンボボックスのリスト部分が非表示のときは、メッセージを返さない If SendMessage(hwnd, CB_GETDROPPEDSTATE, ByVal 0&, ByVal 0&) = 0 Then GoTo PGMEXIT End If 'キーアップ Case WM_KEYUP 'wParamにはキーコードが入る Select Case wParam 'カーソル↑← Case vbKeyUp, vbKeyLeft '1バイト目のフラグをおろす bytKeyFlg = bytKeyFlg And (Not KEY_UP) 'カーソル↓→ Case vbKeyDown, vbKeyRight '2バイト目のフラグをおろす bytKeyFlg = bytKeyFlg And (Not KEY_DOWN) End Select 'クリックやEnter入力時の処理 Case WM_COMMAND 'カーソル↑←やカーソル↓→が移動するたびに、値を設定してしまうのを防ぐ If bytKeyFlg > 0 Then 'カーソルキーのフラグがたっているので、メッセージを返さない GoTo PGMEXIT End If '強制的にDROPDOWNリストを閉じる Call SendMessage(hwnd, CB_SHOWDROPDOWN, 0&, ByVal 0&) End Select PGMEND: comboProc = CallWindowProc(pLngProc, hwnd, uMsg, wParam, lParam) PGMEXIT: End Function -----標準モジュール(ここまで)-----
その他の回答 (5)
- TAGOSAKU7
- ベストアンサー率65% (276/422)
すいません。さっきのエラーです。+書き忘れです。 書き忘れは、コンボボックスのスタイルがドロップダウンリスト限定だと言うことです。ドロップダウンコンボのままでは無意味です。 エラーはカーソルで選んでエンターを押してもクリックイベントが発生しません。。。もうちょっと研究が必要です。。。m(__)m
- TAGOSAKU7
- ベストアンサー率65% (276/422)
> SendMessage Combo1, CB_SHOWDROPDOWN, 1, 0 の書き方が違います SendMessage Combo1.hwnd, CB_SHOWDROPDOWN, 1, 0 が正しい書き方です。 でもこのAPI、ドロップダウンリストの表示/非表示の切り替えをするだけで、仕様を満たさないのではないのでしょうか?
- todo36
- ベストアンサー率58% (728/1234)
Private Sub Combo1_KeyDown(KeyCode As Integer, Shift As Integer) If (KeyCode = vbKeyDown Or KeyCode = vbKeyUp) Then SendMessage Combo1, CB_SHOWDROPDOWN, 1, 0 End If End Sub
- TAGOSAKU7
- ベストアンサー率65% (276/422)
多分VBの標準機能では無理のような気がします。 あるといえば、 1.コンボボックスのプロセスを監視 2.キーダウンイベントにフラグを立てる 3.フラグによりテキストの変更を破棄させる といったような処理ですが、プロセス監視は結構ムズイですよ。 デバッグもしづらいし。。。
- TAGOSAKU7
- ベストアンサー率65% (276/422)
オブジェクトは何ですか?コマンドボタンですか? ↓・↑はカーソルキーですか? 何らかのオブジェクトの上でカーソルキーを押したら、クリックイベントが発生するのを回避したいという捕らえ方でよろしいですか?
補足
やりたいことは、comboBoxでF4をおして内容を画面上に出力して クリックされたときは、Enterと同じように選択さらた内容をとりこみ 次の項目にいきたいのです。 また、↑・↓は青の帯びが上下するだけにしたいのですがどうすればいいですか またComboBoxには名称とコードをもたして ComboBox.Textには名称のみ表示したいのですが なかなかうまくいきません、これも何かいい方法はないのですか? 教えてください。