リストビューのカラムヘッダのMouseMove

[戻る]
アレン 2008/04/09(水) 11:17:31
現在VS2005 CLI環境で開発しております。

リストビューのヘッダの項目にマウスを動かしたときに、
マウス上の項目名を取得したいのですが、
MouseMoveイベントがヘッダ上だと発生しません。

ヘッダのMouseMoveイベントを取得したい場合、
どのような事をすればよいのでしょうか?

何かわかる方がいましたら、
ご教授していただけませんでしょうか?

宜しくお願いいたします。

アレン 2008/04/10(木) 13:28:56
WndProcを利用すればよいかと思い、 

   virtual void WndProc(Message% m) override 
    {
        switch(m.Msg)  {
        case WM_MOUSEMOVE:
        {
    __super::WndProc(m);


    pt = Cursor->Position;
    pp = listView_StatusNoAuth->PointToClient(pt);
    if ((0<= pp.X) && ( 0 <= pp.Y)) {
      やりたい処理
         }

    return;
        }
        __super::WndProc(m);
    }

としたのですが、マウスがフォームの直下にあるときは呼ばれるのですが、
肝心のリストビューに入ったときは呼ばれずにダメでした。

なので、今度はWM_NCMOUSEMOVEで試したのですが、
ウインドウの枠から外れたときだけで、リストビューに入ったときは呼ばれませんでした。

リストビューのカラムヘッダ上にあるMouseMoveイベントは、
取る方法がないということなのでしょうか?

gak 2008/04/10(木) 16:25:22
1、System::Windows::Forms::NativeWindow から派生したクラス(A)で WndProc() を
override
2、(A)::WndProc() にやりたい事書く
3、適当なタイミング(フォームload時等)で
 (A)->AssignHandle((System::IntPtr)::SendMessage(
     reinterpret_cast<HWND>((リストビュー)->Handle.ToInt32()), LVM_GETHEADER,
0, 0));

bun 2008/04/11(金) 09:42:24
やってみたわけではないので、全く自信はありませんが、
  CListCtrl::GetHeaderCtrl()
の戻り値を
  CHeaderCtrl
の派生クラスでAttach()して、その派生クラスに
  WM_MOUSEMOVE
のハンドラを用意してみてはいかがでしょう。

はずしてたらスイマセン。

アレン 2008/04/11(金) 11:43:44
gakさん、bunさん、情報ありがとうございます。

取り掛かりの道がまったくみえていなかったので、
これらの情報はとてもありがたいです。

あまり経験がないので時間がかかるかもしれませんが、
これから、これらの情報を元に試してみます。

gak 2008/04/11(金) 16:51:53
> あまり経験がないので時間がかかるかもしれませんが、
という事なので一言助言。
俺とbunさんの書いている内容は基本的に同じ。.netクラスライブラリを使うかMFCを使う
かの違いだけです。

>   CHeaderCtrl
> の派生クラスでAttach()して、その派生クラスに
ウィンドウプロシージャを置き換えなきゃいけないんで Attach() では無く
  SubclassWindow()
ですね。

bun 2008/04/11(金) 17:27:05
gakさん、アレンさん、どうもです。

よく見たら、VS2005 CLI環境とありましたね。
MFCの例を載せてしまって失礼しました。

アレン 2008/04/11(金) 19:33:48
Form上でNativeWindowのクラスは定義できるのですが、
gcnewやAssignしようとすると

"規定のコンストラクタがありません"
"認識できない型が使われてます"

のメッセージがでてコンパイルできません。
なぜでしょうか?

以下ソース抜粋

namespace XXX {

    using namespace System;
         いろいろ定義
    ref class NewNativeWindow; 

    public ref class Form1 : public System::Windows::Forms::Form
    {
        private:
        NewNativeWindow^ NaWin;//これだけならコンパイルできる。

        Form1(void) {
            NaWin = gcnew NewNativeWindow(this); // 通らない
        }

        private: System::Void Form1_Load(System::Object^  sender, 
System::EventArgs^  e) {

             NaWin->AssignHandle((System::IntPtr)::SendMessage
(reinterpret_cast<HWND>(listView_StatusNoAuth->Handle.ToInt32()), 
LVM_GETHEADER, 0, 0)); //通らない

        }
    };

    /************ NativeWindow **************/

    ref class NewNativeWindow: public NativeWindow
    {
        Form1 ^frmParent;

public:
        NewNativeWindow(Form1 ^parent)  {
 
           frmParent->HandleCreated += gcnew EventHandler( this, 
&NewNativeWindow::OnHandleCreated );

           frmParent->HandleDestroyed += gcnew EventHandler( this, 
&NewNativeWindow::OnHandleDestroyed );

           this->frmParent = parent;
 
        } 

        internal:
        void OnHandleCreated( Object^ sender, EventArgs^ /*e*/ ) { 
            AssignHandle( (dynamic_cast<Form1^>(sender))->Handle);
        } 

        void OnHandleDestroyed(Object^ sender, EventArgs^ /*e*/) { 
            ReleaseHandle(); 
        } 

        protected:
        virtual void WndProc(Message% m) override {
            やりたいこと
        }
    };
}

K 2008/04/12(土) 00:27:50
NewNativeWindowはForm1より前に定義されていますか?
コンストラクタやメソッドを呼び出しているので、
ref class NewNativeWindow; 
だけでは不十分です。

アレン 2008/04/14(月) 12:10:51
単純にNewNativeWindowをForm1より前にもってくると、
今度はForm1が定義されていないとなってしまったので四苦八苦しましたが、
以下のようにしたらコンパイルは通りました。

ただ、リストビューのヘッダのMOUSE_MOVEは相変わらず発生しないようです。

namespace XXX {

    using namespace System;
         いろいろ定義
    ref class NewNativeWindow; 

    public ref class Form1 : public System::Windows::Forms::Form
    {
        private:
        NewNativeWindow^ NaWin;

        private: System::Void Form1_Load(System::Object^  sender, 
System::EventArgs^  e); // ここは定義だけ

        
    };

    /************ NativeWindow **************/

    ref class NewNativeWindow: public NativeWindow
    {
        Form1 ^frmParent;

public:
        NewNativeWindow(Form1 ^parent)  {
 
           parent->HandleCreated += gcnew EventHandler( this, 
&NewNativeWindow::OnHandleCreated );

           parent->HandleDestroyed += gcnew EventHandler( this, 
&NewNativeWindow::OnHandleDestroyed );

           this->frmParent = parent;
 
        } 

        internal:
        void OnHandleCreated( Object^ sender, EventArgs^ /*e*/ ) { 
            AssignHandle( (dynamic_cast<Form1^>(sender))->Handle);
        } 

        void OnHandleDestroyed(Object^ sender, EventArgs^ /*e*/) { 
            ReleaseHandle(); 
        } 

        protected:
        virtual void WndProc(Message% m) override {

            switch(m.Msg)  {
            case WM_MOUSEMOVE:
            {
                __super::WndProc(m); // リストビューのヘッダでマウスを動かしてもこ
ない
                pt = frmParent->Cursor->Position; // マウスの場所特定
                pp = frmParent->listView->PointToClient(pt); // リストビューの位
置に変換

                やりたいこと

             }
            
         }
    };

    /****** NewNativeWindowクラスを呼んでいるのは後で定義 ******/

    System::Void Form1::Form1_Load(System::Object^  sender, 
System::EventArgs^  e) {

             NaWin = gcnew NewNativeWindow(this); // 通る
             NaWin->AssignHandle((System::IntPtr)::SendMessage
(reinterpret_cast<HWND>(listView->Handle.ToInt32()), 
LVM_GETHEADER, 0, 0)); //通る

        }
}

gak 2008/04/14(月) 16:16:58
ソース示した方が楽そうなので関連する部分の必用最低限のソース出す。
--------------------------------
  ref class NewNativeWindow: public NativeWindow
  {
      protected: virtual void WndProc(Message% m) override {
          やりたいこと
      }
  };

  public ref class Form1 : public System::Windows::Forms::Form
  {
      private:
          NewNativeWindow^ NaWin;
      private:
          System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e)
          {
              NaWin = gcnew NewNativeWindow();
              // NewNativeWindowにリストビューのヘッダを割り当てる
              NaWin->AssignHandle(
                  // Win32APIのSendMessage()を利用してリストビューのヘッダの
                  // ウィンドウハンドルを得る
                  (System::IntPtr)::SendMessage(
                      (HWND)(listView->Handle.ToInt32()),
                      LVM_GETHEADER, 0, 0
                  )
              );
          }
  };
--------------------------------

> ただ、リストビューのヘッダのMOUSE_MOVEは相変わらず発生しないようです。
NewNativeWindowにはリストビューのヘッダをassignしないといけないが、提示ソースで
はそうならないから。
> void OnHandleCreated( Object^ sender, EventArgs^ /*e*/ ) { 
>     AssignHandle( (dynamic_cast<Form1^>(sender))->Handle);
> }
によって最初にForm1がNewNativeWindowにassignされる。
なので Form1::Form1_Load() の段階でリストビューのヘッダをassignしようとしても×。
http://msdn2.microsoft.com/ja-jp/library/system.windows.forms.nativewindow.assignhandle(VS.80).aspx

アレン 2008/04/14(月) 19:05:31
OnHandleCreated,OnHandleDestroyedを削除して、
リストビューのヘッダをassignするようにしたのですが、
やはり、ヘッダ上でマウスを動かしてもMOUSEMOVEイベントがこないようです。

namespace XXX {

    using namespace System;
         いろいろ定義
    ref class NewNativeWindow; 

    public ref class Form1 : public System::Windows::Forms::Form
    {
        private:
        NewNativeWindow^ NaWin;

        private: System::Void Form1_Load(System::Object^  sender, 
System::EventArgs^  e); // ここは定義だけ

        
    };

    /************ NativeWindow **************/

    ref class NewNativeWindow: public NativeWindow
    {
        Form1 ^frmParent;

public:
        void Setting(Form1 ^parent)  { 
           this->frmParent = parent; 
        } 

        protected:
        virtual void WndProc(Message% m) override {

            switch(m.Msg)  {
            case WM_MOUSEMOVE:
            {
                __super::WndProc(m); // リストビューのヘッダでマウスを動かしてもこ
ない
                pt = frmParent->Cursor->Position; // マウスの場所特定
                pp = frmParent->listView->PointToClient(pt); // リストビューの位
置に変換

                やりたいこと

             }
            
         }
    };

    /****** NewNativeWindowクラスを呼んでいるのは後で定義 ******/

    System::Void Form1::Form1_Load(System::Object^  sender, 
System::EventArgs^  e) {

             NaWin = gcnew NewNativeWindow(); // 通る
             NaWin->AssignHandle(
        (System::IntPtr)::SendMessage(
         reinterpret_cast<HWND>(listView->Handle.ToInt32()), 
         LVM_GETHEADER, 0, 0)); //通る

             NaWin->Setting(this);

        }
}

gak 2008/04/15(火) 16:52:05
わからんなぁ。
提示ソースの WndProc(Message% m) では WM_MOUSEMOVE がきた時しか
__super::WndProc(m); を呼んでいない点が気になるといえば気になるけど…2008/04/10
(木) 13:28:56 投稿のソースだと呼んでいるので今回掲示を省略しただけポイしなぁ。

・Win32API ::SendMessage() でヘッダのウィンドウハンドルの取得に成功しているか
・NaWin->AssignHandle() は成功しているか
・WndProc() そのものは呼ばれているか
・WndProc() は処理されているが WM_MOUSEMOVE メッセージだけ捕まえられないのか
・新規プロジェクトを作成して必要最低限のコードのみを組み込んだexeで試しても×か

とりあえず上記点を潰した後でも問題点が露見しないようなら別手段を模索すべきかと。
ただ俺の環境ではxp、vista(共に.net2.0sp1)で期待通りの動作を確認できたから無理
ではないと思うが

gak 2008/04/15(火) 17:29:47
この方法はWin32APIが使えない環境では当然ダメですよ。
改めて書くまでもないと思うけど。

アレン 2008/04/16(水) 14:31:53
[[解決]]
>・Win32API ::SendMessage() でヘッダのウィンドウハンドルの取得に成功しているか

値が入っていましたので大丈夫かと思います。

>・NaWin->AssignHandle() は成功しているか

NaWin->AssignHandleに対して
try catchで例外が発生が発生していないようなので成功していると思います。

>・WndProc() そのものは呼ばれているか

フォームが作成されるときに、WndProc自体は呼ばれているようです。

>・WndProc() は処理されているが WM_MOUSEMOVE メッセージだけ捕まえられないのか

上記のことからWM_MOUSEMOVEメッセージだけ捕まえられないようです。


>・新規プロジェクトを作成して必要最低限のコードのみを組み込んだexeで試しても×か

最低限のコードで試したところうまくいきました。
なので、アプリ内で何かしてしまっているのだと思います。

あとは、一つ一つ追っていこうと思います。

というわけで、本件は一旦解決としておきます。

gakさんにはとてもお世話になりました。
本当にありがとうございました。

アレン 2008/04/17(木) 10:22:52
自分のソースだとうまく行かない理由がわかりました。

Form1にリストビューを表示しているのですが、
リストビューのほかにいろいろなパネルを切り替えて表示していて、
その方法が、

Form1>表示パネル>リストボックス or パネルA or パネルB

のように切り替えるのに
表示パネルのControls->Clear() → Controls->Add(リストボックス)
として実現していました。

しかし、Clear()→Addでリストボックスのハンドルが変わってしまうために
Form1_Loadで渡しても無反応状態になってしまうのが原因のようです。

そこで、

Form1>表示パネル>リストボックスパネル or パネルA or パネルB

のようにして、パネルを一つはさむことによって、
ハンドルが変更されるのはリストボックスのパネルにして、
リストボックスのハンドルは変更されないように修正したところ、
うまく行くようになりました。

これで自分の問題の方も無事解決されました。
ありがとうございました。

古いスレッドには追加発言できません。