C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

No.57305 の関連記事表示

<< 0 >>
■57305  マウスカーソルがタイトルバー上かを検知
□投稿者/ ken -(2011/02/22(Tue) 12:13:55)

    分類:[C++/CLI] 

     Visual C++ 2010 expressでマウス位置の検知を用いたフォームアプリケーションを作成しています。しかし、クライアント領域はともかくとしても、タイトルバー上などは、WndProcをオーバーライドする手法しか無理と言うことが分かりました。

    WM_NCHITTEST = &H84

    を用いれば良いようですが、具体的な記述方法が分かりません。オーバーライドはクラスビュー上でオーバーライドしたいクラス(例えばForm1)を選択しておき、プロパティーのオーバーライドボタンを押せば記述できるのような説明も見つけましたが、Form1を選択しても、表示されているボタンは項目順、アルファベット順、プロパティページのみでオーバーライドボタンは見つかりませんし…。
     書いている質問から初心者であることは分かると思いますが、よろしくお願い致します。
親記事 /過去ログ96より / 関連記事表示
削除チェック/

■57329  Re[1]: マウスカーソルがタイトルバー上かを検知
□投稿者/ shu -(2011/02/22(Tue) 23:17:28)
    2011/02/22(Tue) 23:17:42 編集(投稿者)

    No57305 (ken さん) に返信

    VB.NETのコードですが参考までタイマーコントロールにて

    pt...マウスの座標
    bd...フォーム全体の領域
    clbd...クライアント部分の領域(スクリーン座標に変換)
    bd内でclbdより上にマウス座標があればタイトル部にマウスカーソルがあります。
      bd.left <= pt.x <= bd.left + bd.width かつ bd.y <= pt.y < clbd.y
    こんな感じの条件でみればよいと思います。
    CLIなので多分同じ処理が出来ると思います。

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    Dim pt = Control.MousePosition
    Dim bd = Me.DesktopBounds
    Dim clBd = New Rectangle(Me.PointToScreen(Me.ClientRectangle.Location), Me.ClientSize)

    Label1.Text = String.Format("({0}, {1})", pt.X, pt.Y) & Environment.NewLine &
    String.Format("({0}, {1}, {2}, {3})", bd.X, bd.Y, bd.Width, bd.Height) & Environment.NewLine &
    String.Format("({0}, {1}, {2}, {3})", clBd.X, clBd.Y, clBd.Width, clBd.Height) & Environment.NewLine
    End Sub
記事No.57305 のレス /過去ログ96より / 関連記事表示
削除チェック/

■57331  Re[1]: マウスカーソルがタイトルバー上かを検知
□投稿者/ 魔界の仮面弁士 -(2011/02/22(Tue) 23:39:24)
    No57305 (ken さん) に返信
    >  Visual C++ 2010 expressでマウス位置の検知を用いたフォームアプリケーションを作成しています。
    何のためにマウス位置を検知したいのかにもよりますが、
    Timer で定期的に Cursor->Position を調べるというのは駄目でしょうか。
    
    
    > WM_NCHITTEST = &H84
    &H84 は VB の文法ですね。(^^;) 
    
    
    > プロパティページのみでオーバーライドボタンは見つかりませんし…。
    WndProc メソッドをオーバーライドするのであれば、こんな感じかな。
    
    
    private:
      static const int WM_NCHITTEST = 0x84;
    
    protected:
      virtual void WndProc( Message% m ) override
      {
        Form::WndProc(m);
        if( m.Msg != WM_NCHITTEST) return;
    
        // HTCLIENT = 1
        // HTCAPTION = 2
        // HTSYSMENU = 3
        // など(winuser.h で定義されています)
        this->label1->Text = m.Result.ToString();
      }
記事No.57305 のレス /過去ログ96より / 関連記事表示
削除チェック/

■57362  Re[2]: マウスカーソルがタイトルバー上かを検知
□投稿者/ kenken -(2011/02/23(Wed) 23:28:03)
    > private:
    > static const int WM_NCHITTEST = 0x84;
    >
    > protected:
    > virtual void WndProc( Message% m ) override
    > {
    > Form::WndProc(m);
    > if( m.Msg != WM_NCHITTEST) return;
    >
    > // HTCLIENT = 1
    > // HTCAPTION = 2
    > // HTSYSMENU = 3
    > // など(winuser.h で定義されています)
    > this->label1->Text = m.Result.ToString();
    > }

     ありがとうございます。これで少なくとも境界上はm.Resultが18で検知できることがわかりましたし動作しました。
     目的を書いていませんでした。作成しているのはFormアプリケーションで、Form上にマウスがあるとき(クライアント領域だけでなく、フォーム境界やタイトルバー上を含む)と、フォームからそれているときでフォームの不透明度(Opacity)を変えることを目的としています。.Netでもクライアント領域に関してはMouseEnterとMouseLeaveイベントを用いれば可能ですが、ボーダーとタイトルバー上は検知できません。
     よって正確には、例えばタイトルバー上(境界上も以下同じ)にマウスがあることの検知ではなく、フォーム外からタイトルバーにマウスが動いた、もしくは、タイトルバー上からフォーム外へマウスが動いた事の検知がしたいことになります。一方、同じタイトルバー上にマウスがある場合でも、フォームから移動してきたのか、フォームの外から移動してきたのでは動作を変える必要があります。マウスの位置は判定できますが、マウスの変化を検知することは可能ですか?
記事No.57305 のレス /過去ログ96より / 関連記事表示
削除チェック/

■57363  Re[3]: マウスカーソルがタイトルバー上かを検知
□投稿者/ ken -(2011/02/23(Wed) 23:31:49)
    すみません、名前でkenken=kenです。それと、m.Result=18でボーダー上は検知できますが、m.Result=2のタイトルバー上は、なぜか検出できないときがあるようです。
記事No.57305 のレス /過去ログ96より / 関連記事表示
削除チェック/

■57364  Re[3]: マウスカーソルがタイトルバー上かを検知
□投稿者/ shu -(2011/02/24(Thu) 08:51:00)
    No57362 (kenken さん) に返信

    > 。一方、同じタイトルバー上にマウスがある場合でも、フォームから移動してきたのか、フォームの外から移動してきたのでは動作を変える必要があります。マウスの位置は判定できますが、マウスの変化を検知することは可能ですか?

    そうするとやっぱりTimerで見ないと難しいんじゃないかな。他のウィンドウのメッセージまで監視することになるし。
記事No.57305 のレス /過去ログ96より / 関連記事表示
削除チェック/

■57367  Re[3]: マウスカーソルがタイトルバー上かを検知
□投稿者/ 魔界の仮面弁士 -(2011/02/24(Thu) 11:04:04)
    No57363 (ken さん) に返信
    > m.Result=18でボーダー上は検知できますが、
    HTBORDER ですね。これはサイズ変更されないウィンドウ境界なので、
    FormBorderStyle が可変サイズの場合は、別の値になります。
    
    this->ClientRectangle 内の場合は HTCLIENT (1 : クライアント領域) ですね。
    
    
    > m.Result=2のタイトルバー上は、なぜか検出できないときがあるようです。
    検出できなかった場合、何が渡されましたか?
    
    WM_NCHITTEST による検出がうまくいかないようであれば、
    gcnew Point(m.LParam.ToInt32()) の座標をもとにして
    自分で m.Result をセットするという選択肢もあります。
    
    タイトルバー部に関係ありそうなところだと、Result としては
     HTCAPTION   (2 : タイトルバー領域) 
     HTSYSMENU   (3 : コントロールメニュー) 
     HTMINBUTTON (8 : 最小化ボタン)
     HTMAXBUTTON (8 : 最大化ボタン)
     HTCLOSE    (20 : 閉じるボタン)
    あたりですかね。あとはボーダー系。
    # あえて別の値を返しても構いませんが。
    
    
    ■No57364 (shu さん) に返信
    > そうするとやっぱりTimerで見ないと難しいんじゃないかな。
    > 他のウィンドウのメッセージまで監視することになるし。
    
    WM_NCHITTEST や WM_SETCURSOR は基本的に、カーソルが自ウィンドウ内に
    あるときにしか飛んできませんしね。
    
    
    とりあえず、Timer での実装例。
    マウスポインタが自フォーム上なら不透明、フォーム外なら透明度 50% です。
    
    private:
      void UpdateOpacity()
      {
        double opacity = Bounds.Contains(Cursor->Position) ? 1.0 : 0.5;
        if (Opacity != opacity) Opacity = opacity;
      }
    private:
      void Form1_Load(Object^  sender, EventArgs^  e)
      {
        UpdateOpacity();
        timer1->Interval = 100; //ここの値はお好みで
        timer1->Start();
      }
    private:
      void timer1_Tick(Object^  sender, EventArgs^  e)
      {
        UpdateOpacity();
      }
記事No.57305 のレス /過去ログ96より / 関連記事表示
削除チェック/

■57390  Re[4]: マウスカーソルがタイトルバー上かを検知
□投稿者/ ken -(2011/02/24(Thu) 17:48:48)
    ありがとうございます。プログラムの使い勝手から少し仕様を変えようと思います。

    フォームを透明化するイベント→フォームからフォーカスが失われたとき
    フォームを非透明化するイベント→フォーム(クライアント領域+キャプション領域など)にマウスカーソルが達したとき。

     WM_NCHITTESTで非透明化するイベントを拾おうとすると、例えばキャプション領域にマウスカーソルを留め続けると、次々にイベントが起こってしまい、CPUを全て食ってしまうようです。最初にカーソルがやってきた初回のみ行動を起こすには、前回のWM_NCHITTESTの値を保存しておき、値が同じであったら、非透明化処理をするルーチンを呼び出さないみたいな処置しかないものでしょうか。
記事No.57305 のレス /過去ログ96より / 関連記事表示
削除チェック/

■57393  Re[5]: マウスカーソルがタイトルバー上かを検知
□投稿者/ 魔界の仮面弁士 -(2011/02/24(Thu) 19:44:59)
    No57390 (ken さん) に返信
    > 例えばキャプション領域にマウスカーソルを留め続けると、
    > 次々にイベントが起こってしまい、CPUを全て食ってしまうようです。
    あれ?
    
    マウスを動かしていないのであれば、ウィンドウの状態が変化したりしない限り、
    WM_NCHITTEST は流れてこないと思いますが…。
    
    protected: virtual void WndProc( Message% m ) override
    {
      Form::WndProc(m);
      if( m.Msg != WM_NCHITTEST) return;
      listBox1->Items->Insert(0, m.ToString());
    }
    
    で。タイマーによる実装だと、何か都合が悪かったのでしょうか?
    あれなら、WM_NCHITTEST / MouseLeave / MouseEnter の処理も不要になるように思えますが…。
記事No.57305 のレス /過去ログ96より / 関連記事表示
削除チェック/

■57430  Re[6]: マウスカーソルがタイトルバー上かを検知
□投稿者/ ken -(2011/02/25(Fri) 23:22:32)
    2011/02/28(Mon) 11:00:35 編集(投稿者)
    2011/02/26(Sat) 00:08:43 編集(投稿者)

    どうもありがとうございます。
    うまく行きました。
記事No.57305 のレス / END /過去ログ96より / 関連記事表示
削除チェック/

■57431  Re[7]: マウスカーソルがタイトルバー上かを検知
□投稿者/ 魔界の仮面弁士 -(2011/02/25(Fri) 23:31:30)
    No57430 (ken さん) に返信
    > 以下のように記述してみたのですが、タイマーのイベントが起きていないようです。
    そりゃまぁ、timer1 の Tick イベントに timer1_Tick を割り当てていませんし。


    > System::Windows::Forms::Timer^ timer1 = gcnew System::Windows::Forms::Timer;//この行追加
    コードで直書きせず、デザイナから貼り付けましょう。

    そうすれば Visual Studio によって、 void InitializeComponent(void) 内に
     this->timer1 = (gcnew System::Windows::Forms::Timer(this->components));
     this->timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
    といったコードが自動生成され、イベント発生時に timer1_Tick が呼ばれるようになるはずですよ。
記事No.57305 のレス /過去ログ96より / 関連記事表示
削除チェック/

■57458  Re[8]: マウスカーソルがタイトルバー上かを検知
□投稿者/ ken -(2011/02/28(Mon) 11:02:17)
    2011/02/28(Mon) 11:06:48 編集(投稿者)

    すみません、前後して気がつきました。所望動作できるようになりました。ありがとうございました。
    ところで、
    Bounds.Contains(Cursor->Position) ? 1.0 : 0.5;
    の記述を初めて見たのですが、?より前が条件式、その後のコロンで区切られた2つの数値が、条件式がtrueおよびfalseの戻り値でよいのですよね。
記事No.57305 のレス / END /過去ログ96より / 関連記事表示
削除チェック/



<< 0 >>

パスワード/

- Child Tree -