リストボックスでのW/Sクリックの区別

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
淡幻星
記事: 183
登録日時: 2005年7月19日(火) 07:02
お住まい: 宮城県
連絡する:

リストボックスでのW/Sクリックの区別

#1 投稿記事 by 淡幻星 »

リストボックスで、項目がダブルクリックされた場合と、
シングルクリックされた場合の区別の仕方がわかりません。

通知コードも、軽く検索掛けた限りでは
LBN_DBLCLK 項目をダブルクリックした時。
LBN_ERRSPACE リストボックスがメモリを取得できない時。
LBN_KILLFOCUS キーボードフォーカスを失った時。
LBN_SELCANCEL 選択項目をキャンセルした時。
LBN_SELCHANGE 選択項目に、何らかの変更があった時。
LBN_SETFOCUS キーボードフォーカスを得た時。
しかないように思われます。

LBN_SELCHANGE → Sクリック
LBN_DBLCLK → Wクリック

で区別しようとすると、全てLBN_SELCHANGEになってしまいます。

一応、リストボックスのIDをListBoxOutputUrlとして、

コード: 全て選択

Dim MainWndProc_nListSglClickFrag As Long
Const TimerID_ListWS = 1024

'-----------------------------------------------------------------------------
' ウィンドウメッセージを処理するためのコールバック関数

Function MainWndProc(hWnd As DWord, dwMsg As DWord, wParam As DWord, lParam As DWord) As DWord
	' TODO: この位置にウィンドウメッセージを処理するためのコードを記述します。

	SelectCase dwMsg
	Case WM_COMMAND
		SelectCase LOWORD(wParam)
		Case ListBoxOutputUrl
			Select Case HIWORD(wParam)
			Case LBN_SELCHANGE
				SetTimer( hMainWnd, TimerID_ListWS, GetDoubleClickTime(), NULL )
				MainWndProc_nListSglClickFrag = TRUE
			Case LBN_DBLCLK
				MainWndProc_nListSglClickFrag = FALSE
				Msgbox hWnd, "Wクリック"
			End Select
		EndSelect
	Case WM_TIMER
		If( wParam=TimerID_ListWS )Then
			KillTimer( hMainWnd, TimerID_ListWS )
			If( MainWndProc_nListSglClickFrag=TRUE )Then
				Msgbox hWnd, "Sクリック"
			EndIf
			MainWndProc_nListSglClickFrag = FALSE
		EndIf
	EndSelect

	' イベントプロシージャの呼び出しを行います。
	MainWndProc=EventCall_MainWnd(hWnd,dwMsg,wParam,lParam)
End Function
Ver3.13 + RAD

の様に組むことで、区別はできたのですが、
何かもっと楽な方法や通知コードを知っている方いらっしゃいましたら、
教えていただけないでしょうか?

それとも、このように自前で区別するしかないのでしょうか?
hira
記事: 203
登録日時: 2005年5月31日(火) 20:14
お住まい: 兵庫県
連絡する:

Re: リストボックスでのW/Sクリックの区別

#2 投稿記事 by hira »

試していませんが、リストボックスそのものをサブクラス化して通常のWM_LBUTTONUPやWM_LBUTTONDBLCLKを監視すればできるかもしれません。
NoWest
記事: 264
登録日時: 2005年5月31日(火) 10:52
お住まい: 高知
連絡する:

Re: リストボックスでのW/Sクリックの区別

#3 投稿記事 by NoWest »

> 試していませんが、リストボックスそのものをサブクラス化して通常のWM_LBUTTONUPやWM_LBUTTONDBLCLKを監視すればできるかもしれません。
こんな感じになります。

コード: 全て選択

Dim DefListBoxProc As DWord
Function NewListBoxProc(hWnd As DWord, dwMsg As DWord, wParam As DWord, lParam As DWord) As DWord
	Select Case dwMsg
		Case WM_LBUTTONDBLCLK
			Beep(100,100)/* ダブルクリックの処理 */
			Exit Function
	End Select
	NewListBoxProc=CallWindowProc(DefListBoxProc,hWnd,dwMsg,wParam,lParam)
End Function

'-----------------------------------------------------------------------------
' ここから下は、イベントプロシージャを記述するための領域になります。

Sub MainWnd_Destroy()
	SetWindowLong(GetDlgItem(hMainWnd,ListBox1),GWL_WNDPROC,AddressOf(NewListBoxProc))
	l_DestroyObjects()
	PostQuitMessage(0)
End Sub


Sub MainWnd_Create(ByRef CreateStruct As CREATESTRUCT)
	DefListBoxProc=GetWindowLong(GetDlgItem(hMainWnd,ListBox1),GWL_WNDPROC)
	SetWindowLong(GetDlgItem(hMainWnd,ListBox1),GWL_WNDPROC,AddressOf(NewListBoxProc))
End Sub
基本的にあらゆるコントロールはそれぞれコントロール固有のウィンドウプロシージャを持っているのでそちらを独自のものに変更することでより細かな制御が可能です。へたするとサブクラス化を使用したほうがソースがより見易くなったり、スッキリすることもあるので使ってみるとよいと思います。

あと、

コード: 全て選択

			Beep(100,100)/* ダブルクリックの処理 */
			Exit Function
としているのですが
このExit Functionを除くと親ウィンドウにLBN_SELCHANGEが送られる??のではないかと思います。

どうしてLBN_DBLCLKの代わりにLBN_SELCHANGEが送られてくるのかは分かりませんが、もしかしたらListBoxのダブルクリックを許可するListBoxスタイルか拡張スタイルがあるのかもしれません。
淡幻星
記事: 183
登録日時: 2005年7月19日(火) 07:02
お住まい: 宮城県
連絡する:

Re: リストボックスでのW/Sクリックの区別

#4 投稿記事 by 淡幻星 »

hira さん、NoWestさん、ありがとうございます。

NoWestさんの示してくださった方法でやってみましたが、
どうやら[ WM_LBUTTONDBLCLK ]は、[ WM_LBUTTONDOWN ]などの
メッセージが流された後に(よって親ウィンドウに[ LBN_SELCHANGE ]が送られた後に)
連続して再び[ WM_LBUTTONDOWN ]が来た場合に流される、という形式みたいです。
なので、Sクリック時の処理が存在すると、一回目のクリックの時点で
とにもかくにもそちらの処理を実行してしまうので、[ WM_LBUTTONDBLCLK ]は
流れてこないみたいでした。

なので、当面のW/Sクリックの区別は、
先の(Timerを使う)方法でしようと思います。
拡張スタイルなどは、そのうちゆっくり調べてみようと思います。

なお、

コード: 全て選択

Sub MainWnd_Destroy()
    SetWindowLong(GetDlgItem(hMainWnd,ListBox1),GWL_WNDPROC,AddressOf(NewListBoxProc))
    l_DestroyObjects()
    PostQuitMessage(0)
End Sub

コード: 全て選択

Sub MainWnd_Destroy()
    SetWindowLong(GetDlgItem(hMainWnd,ListBox1),GWL_WNDPROC,DefListBoxProc)
    l_DestroyObjects()
    PostQuitMessage(0)
End Sub
のミスのように思いましたので、そう記述しました。


サブクラス化は難しそうだったので、手を出すつもりはありませんけど、
そうでもないんですね(とは、サンプルコードを載せていただいたから言える台詞^^;)
これを使うとリストボックス上での右クリックなんかも拾えるんですね。
もともと、左W/右Sクリックで動作分岐を考えていたんですが、
リストボックス上での右クリックの拾い方が分からなかったので、
しかたなく、左W/左Sクリックでの動作分岐に代えていたのでしたが、
これで幅が広がります。

ありがとうございました。
返信する