TreeViewのスクロールのマウスホイール有効、無効化 – プログラミング – Home

TreeViewのスクロールのマウスホ...
 
通知
すべてクリア

[解決済] TreeViewのスクロールのマウスホイール有効、無効化


マコ
 マコ
(@マコ)
ゲスト
結合: 14年前
投稿: 8
Topic starter  

マルチウィンドウ上(MDIではない)で、ひとつをTreeView、他のウィンドウをスクロール
対応にしています。
困ったことにTreeViewはどのウィンドウ上にマウスがあっても、マウスホイールで勝手
にスクロールしてしまいます。
スクロールを実装した別ウィンドウにマウスがある時は、そちらのウィンドウをスクロー
ルさせたいのですが、WM_MOUSEWHEELメッセージが親ウィンドウのプロシージャに届か
ず、うまく行きません。
やむなく
TranslateMassage()前にWM_MOUSEWHEELを捕まえて強制的に動かしたいウィンドウのスク
ロールに成功したのですが、今度はフォーカスをTreeView側に移してもTreeView側のスク
ロールが実行されません。

どうすれば意図するウィンドウのスクロールを有効にすることができるのでしょうか?
コモンコントロールのTreeViewではマウスホイール処理がどのように実装されているので
しょうか?

開発はVC++(VC2003)のSDKでプログラムしています。


引用未解決
トピックタグ
MistyGreen
 MistyGreen
(@MistyGreen)
ゲスト
結合: 14年前
投稿: 17
 

ヘルプによると、以下のような記載がありますね。

WM_MOUSEWHEELは Windows によって、フォーカスのあるコントロールまたは
子ウィンドウに自動的に転送されます。Win32 の関数 DefWindowProc は、
このメッセージを処理するウィンドウに到達するまで、親チェインを
さかのぼってメッセージを転送します。

つまり、何らかのウィンドウでWM_MOUSEWHEELに対してTRUEを返さない限り
処理が終わらない、という意味だと思います。

> ひとつをTreeView、他のウィンドウをスクロール対応にしています。

TreeView以外のスクロール対応のウィンドウのウィンドウプロシージャでは
WM_MOUSEWHEELのイベントハンドラを実装していますか?
また、その処理から戻る時にTRUEを返していますか?

TRUEを返せば、親チェーンをさかのぼることもなくなるような気がします。

> どうすれば意図するウィンドウのスクロールを有効にすることができるのでしょう
か?

「意図するウィンドウ」を判定する条件がはっきりしているのであれば、
TreeViewをサブクラス化して条件外の場合にはWM_MOUSEWHEELをスルーする、
または意図するウィンドウにパスする、という方法もあるかもしれませんね。

今、これを書いていて思い出しました。
HTML ヘルプなどでも左側のTreeViewにフォーカスがある状態で、右側の
コンテンツペイン内でホイールを回転させると、TreeViewの方がスクロール
してしまいますよね。これと同じ現象でしょうか?

このような場合には、やはりTreeViewをサブクラス化してマウスポインタの
座標によって、目的のウィンドウにメッセージをパスするような方法が有効な気がしま
す。

もっと、スマートな方法があるかもしれませんが・・・


返信引用
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 5年前
投稿: 828
 

Windowsのホイールメッセージの実装は、ほんとにばかげてますよね(^^;)。
インターネットエクスプローラはちゃんと処理してるようですし、
自分でバンバンやっちゃいましょう(笑)。
自分の場合は次の要領でやってます。

1.メインフレームのPreTranslateMessage()をオーバーライドする
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg){
// マウスホイールが処理したら戻る
if( TRUE == PreTranslate_MouseWheel( pMsg)){ return TRUE;}
return CMDIFrameWnd::PreTranslateMessage(pMsg);
}
2.PreTranslate_MouseWheel()を実装する
BOOL CMainFrame::PreTranslate_MouseWheel( MSG *msg){
// ホイールメッセージ以外は処理しない
if( msg->message != WM_MOUSEWHEEL) return FALSE;
// メッセージのHWNDが最上位フレームで無い場合は最上位フレームに変更す
// ■これは、マウスをキャプチャーしているコントロールがメッセージを
//  独占するのを防ぎ、現在のカーソル直下の「正しい」コントロールに
//  メッセージを送付したいため。
HWND hwnd_root = ::GetAncestor( msg->hwnd, GA_ROOTOWNER);
msg->hwnd = hwnd_root; // 差し替える
// カーソル直下の子ウインドウを取得する
HWND hwnd_child = ::WindowFromPoint( msg->pt);
if( NULL == hwnd_child) return FALSE;// 子が見つからない場合は未処理で終

// コンボボックスには送らない(迷惑な場合が多いため)
char classname[ 128];
::GetClassNameA( hwnd_child, classname, 128);
if( 0 == ::strcmp( ComboBox, classname)) return FALSE;
// 見つかった子ウインドウにフォーカスを強制し、メッセージを送付する
::SetFocus( hwnd_child); // フォーカスを強制する。一般にこれでキャプチャ
ーが外れる
::SendMessage( hwnd_child, msg->message, msg->wParam, msg->lParam);
return TRUE;
}

さて、SDKの場合はメインメッセージループで当該の関数を呼べばおけのはず

// メイン メッセージ ループ:
MSG msg; // メッセージ
while( ::GetMessage( &msg, NULL, 0, 0)){
// マウスホイールが処理したら戻る
if( TRUE == PreTranslate_MouseWheel( msg)) continue;
// 通常のディスパッチ
::TranslateMessage( &msg);
::DispatchMessage( &msg);
}

注意:GetAncestor()でエラーになるようならプラットホームかエクスプローら
バージョンの指定を変えてくださいね。(どっちだったか失念しました)。
#define _WIN32_WINNT 0x0502
#define _WIN32_IE 0x0600


返信引用
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 5年前
投稿: 828
 

連投失礼m(__)m
先の方法だと、自分以外のWindowにも効果が出てしまいますね。
気に入らなかったら自分のHWNDに限定してください。


返信引用
マコ
 マコ
(@マコ)
ゲスト
結合: 14年前
投稿: 8
Topic starter  

MistyGreenさん、仲澤@失業者さん、親切なご回答ありがとうございます。

MistyGreenさん
>今、これを書いていて思い出しました。
>HTML ヘルプなどでも左側のTreeViewにフォーカスがある状態で、右側の
>コンテンツペイン内でホイールを回転させると、TreeViewの方がスクロール
>してしまいますよね。これと同じ現象でしょうか?
⇒まさにその現象です。

>TreeView以外のスクロール対応のウィンドウのウィンドウプロシージャでは
>WM_MOUSEWHEELのイベントハンドラを実装していますか?
>また、その処理から戻る時にTRUEを返していますか?
⇒TRUEを返していますが、TreeView側には処理が戻りません。

仲澤@失業者さん
私はMFCは使っておりませんが、仲澤@失業者さんのサンプルのようにTranslateMessage
()手前でWM_MOUSEWHEELを捕まえて期待するウィンドウのスクロールを行っています。
でもTreeView側では新たなスクロール処理を実装せずに済ませたいと思っています。
TreeView側のスクロール処理も新たに実装する必要がありますか?
単純にTRUEを返せば、TreeView側に既に実装されている処理がなされるのでしょうか?
極力新たな実装をせずにスマートに行きたいのですが。。

すいません今、手元にソースがないので、週末にでももう一度トライしてみたいと
思います。

お二人さん
まずは、ありがとうございました。


返信引用
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 5年前
投稿: 828
 

>TreeView側のスクロール処理も新たに実装する必要がありますか?

まったく必要ありません。

「連投」の方にも書きましたが、ホイールメッセージを常識的な手順で
処理をしている限り、自分のコードを実装すれば、自分の配下、
また他のウインドウの配下の、マウスカーソル直下の、全てのコントロール
(コンボボックスを除く)にWM_MOUSEWHEELが届きます。

尚、マウス位置はいじっていないので、デスクトップ座標のままになっています。
これは、ほとんどのコントロールがデスクトップ座標のままで、正しく反応する
ことを確かめた結果の仕様です。


返信引用
MistyGreen
 MistyGreen
(@MistyGreen)
ゲスト
結合: 14年前
投稿: 17
 

仲澤さん、フォローありがとうございました。

PreTranslateMessage()で処理した方が断然スマートですね。
私も仲澤さんのコードをストックさせて頂きます。(^_^;

今後ともよろしくお願い致します。


返信引用
マコ
 マコ
(@マコ)
ゲスト
結合: 21年前
投稿: 9
 

半信半疑でPreTranslate_MouseWheel( &msg )を実装してみました。
え!!
あっさり動きました^^/
こういう時は、
::GetAssensor()でルートウィンドウのハンドルを取得するのですね(フムフム)

仲澤@失業者さん、MistyGreenさん
ありがとうございましたm(_ _)m


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました