【.NET】【C#】【WinForm 】マウスでフォーカスされたテキストボックスのテキストを全選択する
マウスでテキストボックスをフォーカスしたときにテキストを全選択する方法についてまとめてみます。
グーグル検索すればStackoverflow等の記事がいくつか見つかりますが、特定条件での挙動が不完全だったので、その辺りの改善も含めて整理しました。
うまくいかない例
パッと思いつく方法としてGotFocusやEnterイベントハンドラでSelectAll()する方法があります。
この方法ではマウスでテキストボックスをフォーカスした場合にうまく全選択されません。
GotFocus/Enterイベント後に発生するマウスイベントで選択状態が解除されてしまうからです。
フォーム配置:
コード:
private void Form1_Load(object sender, EventArgs e) { textBox1.Enter += TextBox1_Enter; textBox1.GotFocus += TextBox1_GotFocus; } private void TextBox1_Enter(object sender, EventArgs e) { textBox1.SelectAll(); } private void TextBox1_GotFocus(object sender, EventArgs e) { textBox1.SelectAll(); }
別の方法として、GotFocusイベント発生後少し待ってからSelectAll()する方法もあります。
参考リンク:https://stackoverflow.com/questions/19095376/net-compactframework-textbox-selectall-on-gotfocus
テキストフォーカス後すぐに範囲選択操作をした場合、範囲選択が解除されてしまうので今一つです。
コード:
private void Form1_Load(object sender, EventArgs e) { textBox1.GotFocus += TextBox1_GotFocus; } private void TextBox1_GotFocus(object sender, EventArgs e) { Timer timer = new Timer { Interval = 100, Enabled = true }; timer.Tick += (EventHandler)delegate { textBox1.SelectAll(); timer.Dispose(); }; }
解決策1
ググって調べた感じでは一番良さそうな方法です。
参考リンク:https://stackoverflow.com/questions/97459/making-a-winforms-textbox-behave-like-your-browsers-address-bar
タブキー/マウスクリックどちらでフォーカスしても全選択されますし、範囲選択操作が邪魔されることもありません。
ただし、非アクティブなフォームのテキストをクリックした場合にテキストが全選択されない欠点があります(解決策2参照)。
フォーム配置:
コード(参考リンクのコードのコメントを日本語化+デバッグメッセージ追加):
bool alreadyFocused; private void Form1_Load(object sender, EventArgs e) { textBox1.GotFocus += TextBox1_GotFocus; textBox1.MouseUp += TextBox1_MouseUp; textBox1.Leave += TextBox1_Leave; } private void TextBox1_GotFocus(object sender, EventArgs e) { Debug.WriteLine("GotFocus"); // マウスが押されていないときにだけテキストを全選択する。 // こうすることによって、タブによるテキストボックスのフォーカスだけを処理する。 if (MouseButtons == MouseButtons.None) { Debug.WriteLine("SelectAll on GotFocus"); textBox1.SelectAll(); alreadyFocused = true; } } private void TextBox1_MouseUp(object sender, MouseEventArgs e) { Debug.WriteLine("MouseUp"); // GoogleクロームのようなWebブラウザではMouseUpのときにテキストを選択している。 // そこでは、テキストボックスがまだフォーカスされていない場合と // ユーザーがテキストを全く選択していない場合にのみ行っている。 if (!alreadyFocused && this.textBox1.SelectionLength == 0) { Debug.WriteLine("SelectAll on MouseUp"); alreadyFocused = true; textBox1.SelectAll(); } } private void TextBox1_Leave(object sender, EventArgs e) { Debug.WriteLine("Leave"); alreadyFocused = false; }
デバッグメッセージ出力:
タブキーでフォーカスされたとき: GotFocus SelectAll on GotFocus … マウスが押されていないのでSelectAll()する マウスクリックでフォーカスされたとき: GotFocus … マウスが押されているのでSelectAll()しない MouseUp SelectAll on MouseUp … SelectAllされていない&テキスト選択されていないのでSelectAll()する マウスクリックでフォーカスし、テキストを選択した場合: GotFocus … マウスが押されているのでSelectAll()しない (テキスト選択中) MouseUp … テキストが選択されているのでSelectAll()しない フォーカスを失ったとき: Leave … alreadyFocusedをfalseにする
解決策2:解決策1の改善版
非アクティブなフォームのテキストをクリックした場合にテキストが全選択されない問題を対策してみます。
原因の調査
このときのデバッグメッセージ出力は次のとおりです:
非アクティブなフォームのテキストをクリックしたとき: GotFocus SelectAll on GotFocus MouseUp フォームを非アクティブにしたとき: (なし)
GotFocusイベントハンドラ内の判定文 (MouseButtons == MouseButtons.None) が真となってSelectAll()が実行され、後続のMouseUpイベントで選択状態が解除されています。
Control.MouseButtonsではUser32.dllのGetKeyStateを呼び出してマウスボタンの状態を取得しています。GetKeyStateの説明には「入力メッセージが生成されたときのキーの状態を取得します」と書かれています。マウス操作でテキストボックスをクリックした延長で発生したイベントですから値が入っていても良さそうですが、とにかく値はMouseButtons.Noneとなってしまいます。
また、フォームを非アクティブにしたときにLeaveイベントが発生しないため、alreadyFocusedが適切にリセットされません。
対策
User32.dllのGetAsyncKeyStateを使って「その瞬間の」マウスボタンの状態を取得します。
Leaveイベントの代わりにLostFocusイベントハンドラでalreadyFocusedをリセットします。
コード:
bool alreadyFocused; [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] private static extern short GetAsyncKeyState(int vkey); private static MouseButtons AsyncMouseButtons { get { MouseButtons buttons = (MouseButtons)0; if (GetAsyncKeyState((int)Keys.LButton) < 0) buttons |= MouseButtons.Left; if (GetAsyncKeyState((int)Keys.RButton) < 0) buttons |= MouseButtons.Right; if (GetAsyncKeyState((int)Keys.MButton) < 0) buttons |= MouseButtons.Middle; if (GetAsyncKeyState((int)Keys.XButton1) < 0) buttons |= MouseButtons.XButton1; if (GetAsyncKeyState((int)Keys.XButton2) < 0) buttons |= MouseButtons.XButton2; return buttons; } } private void Form1_Load(object sender, EventArgs e) { textBox1.GotFocus += TextBox1_GotFocus; textBox1.MouseUp += TextBox1_MouseUp; textBox1.LostFocus += TextBox1_LostFocus; } private void TextBox1_GotFocus(object sender, EventArgs e) { Debug.WriteLine("GotFocus"); // マウスが押されていないときにだけテキストを全選択する。 // こうすることによって、タブによるテキストボックスのフォーカスだけを処理する。 if (AsyncMouseButtons == MouseButtons.None) { Debug.WriteLine("SelectAll on GotFocus"); textBox1.SelectAll(); alreadyFocused = true; } } private void TextBox1_MouseUp(object sender, MouseEventArgs e) { Debug.WriteLine("MouseUp"); // GoogleクロームのようなWebブラウザではMouseUpのときにテキストを選択している。 // そこでは、テキストボックスがまだフォーカスされていない場合と // ユーザーがテキストを全く選択していない場合にのみ行っている。 if (!alreadyFocused && this.textBox1.SelectionLength == 0) { Debug.WriteLine("SelectAll on MouseUp"); alreadyFocused = true; textBox1.SelectAll(); } } private void TextBox1_LostFocus(object sender, EventArgs e) { Debug.WriteLine("LostFocus"); alreadyFocused = false; }
以上
----
記事の履歴
2017/07/13 : 記事作成