トップ回答者
ContextMenuStripのツールチップの表示位置の制御

質問
-
お世話になります。
ToolStripMenuItemにツールチップをセットし表示させています。それ自身問題ないのですが、ツールチップの表示位置が画面の下部に絡む位置に表示されると点滅して見づらくなります。
これを回避する方法はありますでしょうか?
ToolStripMenuItem[,] sub3 = new ToolStripMenuItem[10, 50];
:
sub3[i, k].ToolTipText = shoken[h].Data;
上記のようにループで動的にメニューを作成しています。
サブクラス化してみましたが、ツールチップ表示が拾えませんでした。ご存知でしたら教えてください。
Windows10 C# WinForm
- 移動 立花楓Microsoft employee, Moderator 2018年6月8日 4:35 .Net Framework > .NET Framework
回答
-
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
すべての返信
-
以下が参考になるかもしれません。
How to set tooltip position just beneath the cursor?
https://stackoverflow.com/questions/23712756/how-to-set-tooltip-position-just-beneath-the-cursor★良い回答には質問者は回答済みマークを、閲覧者は投票を!
-
自分も、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); } }
-
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