none
ContextMenuStripのツールチップの表示位置の制御 RRS feed

  • 質問

  • お世話になります。

    ToolStripMenuItemにツールチップをセットし表示させています。それ自身問題ないのですが、ツールチップの表示位置が画面の下部に絡む位置に表示されると点滅して見づらくなります。

     これを回避する方法はありますでしょうか?

    ToolStripMenuItem[,] sub3 = new ToolStripMenuItem[10, 50];

      :

    sub3[i, k].ToolTipText = shoken[h].Data;

    上記のようにループで動的にメニューを作成しています。

    サブクラス化してみましたが、ツールチップ表示が拾えませんでした。ご存知でしたら教えてください。

    Windows10 C# WinForm

    2018年3月28日 2:17

回答

  • ToolStripMenuItemからマウスが離れた時(マウスがツールチップ重なった時)にツールチップが閉じられてしまうみたいなので、マウスが離れた時の処理をしないようにしてみる。

    using System;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                ContextMenuStrip menuStrip = new ContextMenuStrip();
                menuStrip.ShowItemToolTips = true;
    
                ToolStripMenuItemEx menu = new ToolStripMenuItemEx();
                menuStrip.Items.Add(menu);
                menu.Text = "TEST";
                menu.DropDownItems.Add("dummy");
                menu.DropDownOpening += (s, e) =>
                    {
                        for (int i = 0; i < 100; i++)
                        {
                            ToolStripMenuItem submenu = new ToolStripMenuItemEx();
                            submenu.Text = i.ToString();
                            submenu.ToolTipText = "Tooltip " + i.ToString();
    
                            menu.DropDownItems.Add(submenu);
                            submenu.Overflow = ToolStripItemOverflow.Never;
                        }
    
                    };
                menu.DropDownClosed += (s, e) =>
                    {
                        menu.DropDownItems.Clear();
                        menu.DropDownItems.Add("dummy");
                    };
    
                this.ContextMenuStrip = menuStrip;
    
            }
    
            class ToolStripMenuItemEx : ToolStripMenuItem
            {
                [System.Runtime.InteropServices.DllImport("user32.dll")]
                static extern IntPtr WindowFromPoint(System.Drawing.Point p);
                [System.Runtime.InteropServices.DllImport("User32.dll")]
                private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
                [System.Runtime.InteropServices.DllImport("user32.dll")]
                static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
    
                const int TTM_GETCURRENTTOOL = 0x20A + 0xF;
    
                protected override void OnMouseLeave(EventArgs e)
                {
                    System.Diagnostics.Debug.WriteLine("Leave");
    
                    var hwnd = WindowFromPoint(Cursor.Position);//マウスカーソルの下にあるウィンドウを探す
                    if (hwnd != IntPtr.Zero)
                    {
                        uint pid1;
                        uint pid2;
                        if (GetWindowThreadProcessId(hwnd, out pid1) == GetWindowThreadProcessId(this.Owner.Handle, out pid2))
                        {//同じスレッドに属しているウィンドウ
                            var control = Control.FromHandle(hwnd);
                            if (control == null && SendMessage(hwnd, TTM_GETCURRENTTOOL, IntPtr.Zero, IntPtr.Zero) != null)
                            {//ウィンドウはツールチップ
    
                                //ToolTipの上にマウスが乗っている状態の場合にはMouseLeaveと看做されないようにする
                                return;
                            }
                        }
                    }
    
                    base.OnMouseLeave(e);
                }
            }
    
    
        }
    }

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク ferret001 2018年3月29日 2:16
    2018年3月28日 8:39

すべての返信

  • 以下が参考になるかもしれません。

    How to set tooltip position just beneath the cursor?
    https://stackoverflow.com/questions/23712756/how-to-set-tooltip-position-just-beneath-the-cursor


    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    2018年3月28日 5:44
    モデレータ
  • お世話になります。

    ToolTipクラスで作成したのではなく、ToolStripMenuItemのToolTipTextを使用しています。

    ツールチップの詳細をセットするプロパティが少なく苦慮しています。

    TooTipクラスで作成したインスタンスをToolStripMenuItemに代入したりできるのでしょうか?

    2018年3月28日 6:15
  • あ~、すみません。ボケてました。ContextMenuStripはToolStripの派生であって、ToolTipの派生じゃないですね。
    というわけで忘れて下さい。よく考えたら当たり前ですが、読み間違えてしまいました。ごめんなさい。

    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    2018年3月28日 6:33
    モデレータ
  • 自分も、MouseMove イベント+ToolTip.SetToolTip メソッドの組み合わせを使われているかなと思いましたが、違うみたいですね。「c#  ツールチップ 点滅」でググると、ヒットするのがこちら系が多かったので。

    現象の再現が見たいのですが、Windows 8.1 だと出ない(のか、プログラムの作り方なのか)ですね。
    以下のようなテスト画面を作った場合、現象は出ますでしょうか?
    というよりかは、どういう手順だと出ますでしょうか?(タスクバー辺りまで画面をドラッグ移動させて、右クリック→コンテキストメニュー出して、項目にマウスオーバーして、ツールチップを表示してみる?)

    // Form に TextBox を配置している(画面の下部あたり)
    // TextBox.ContextMenuStrip プロパティに、contextMenuStrip1 をセットしている
    private void Form1_Shown(object sender, EventArgs e)
    {
        foreach (var item in Enumerable.Range(1, 10))
        {
            var menuItem = new ToolStripMenuItem();
            menuItem.Text = $"item{item}";
            menuItem.ToolTipText = $"item{item}";
            this.contextMenuStrip1.Items.Add(menuItem);
        }
    }

    2018年3月28日 6:37
  • お世話になります。

    サンプルを試しました。同様に点滅を繰り返しますが、その状況が少しわかりました。

    表示したツールチップがマウスポインタと重なると点滅が始まるようです。うまくずらすと止まりました。

    表示位置を少し右側にずらせればいいかもしれません。

    2018年3月28日 7:09
  • ToolStripMenuItemからマウスが離れた時(マウスがツールチップ重なった時)にツールチップが閉じられてしまうみたいなので、マウスが離れた時の処理をしないようにしてみる。

    using System;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                ContextMenuStrip menuStrip = new ContextMenuStrip();
                menuStrip.ShowItemToolTips = true;
    
                ToolStripMenuItemEx menu = new ToolStripMenuItemEx();
                menuStrip.Items.Add(menu);
                menu.Text = "TEST";
                menu.DropDownItems.Add("dummy");
                menu.DropDownOpening += (s, e) =>
                    {
                        for (int i = 0; i < 100; i++)
                        {
                            ToolStripMenuItem submenu = new ToolStripMenuItemEx();
                            submenu.Text = i.ToString();
                            submenu.ToolTipText = "Tooltip " + i.ToString();
    
                            menu.DropDownItems.Add(submenu);
                            submenu.Overflow = ToolStripItemOverflow.Never;
                        }
    
                    };
                menu.DropDownClosed += (s, e) =>
                    {
                        menu.DropDownItems.Clear();
                        menu.DropDownItems.Add("dummy");
                    };
    
                this.ContextMenuStrip = menuStrip;
    
            }
    
            class ToolStripMenuItemEx : ToolStripMenuItem
            {
                [System.Runtime.InteropServices.DllImport("user32.dll")]
                static extern IntPtr WindowFromPoint(System.Drawing.Point p);
                [System.Runtime.InteropServices.DllImport("User32.dll")]
                private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
                [System.Runtime.InteropServices.DllImport("user32.dll")]
                static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
    
                const int TTM_GETCURRENTTOOL = 0x20A + 0xF;
    
                protected override void OnMouseLeave(EventArgs e)
                {
                    System.Diagnostics.Debug.WriteLine("Leave");
    
                    var hwnd = WindowFromPoint(Cursor.Position);//マウスカーソルの下にあるウィンドウを探す
                    if (hwnd != IntPtr.Zero)
                    {
                        uint pid1;
                        uint pid2;
                        if (GetWindowThreadProcessId(hwnd, out pid1) == GetWindowThreadProcessId(this.Owner.Handle, out pid2))
                        {//同じスレッドに属しているウィンドウ
                            var control = Control.FromHandle(hwnd);
                            if (control == null && SendMessage(hwnd, TTM_GETCURRENTTOOL, IntPtr.Zero, IntPtr.Zero) != null)
                            {//ウィンドウはツールチップ
    
                                //ToolTipの上にマウスが乗っている状態の場合にはMouseLeaveと看做されないようにする
                                return;
                            }
                        }
                    }
    
                    base.OnMouseLeave(e);
                }
            }
    
    
        }
    }

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク ferret001 2018年3月29日 2:16
    2018年3月28日 8:39
  • お世話になります。

    メニュー上のツールチップにマウスがのるとメニューから外れたというウインドウズの仕組みでちらつき(点滅)していたのですね。ちょっと、奥が深いです。

    ありがとうございました。おかげでちらつくことがなくなりました。

    2018年3月29日 2:15