• category: swing folder: SelectAllWhileKeepingVisibleRect title: JTextAreaの全選択で表示領域を維持する tags: [JTextArea, JScrollPane, JTextComponent, ActionMap, InputMap, Caret] author: aterai pubdate: 2025-03-10T00:52:54+09:00 description: JTextAreaの複数行テキストをすべて選択したとき、末尾のキャレット位置までスクロールするのではなく、全選択前の表示領域を維持する全選択アクションを作成します。 image: https://drive.google.com/uc?id=1vbNvUI8-oiwqmf9KVlVeoZCBpsmvZHMb

Summary

JTextAreaの複数行テキストをすべて選択したとき、末尾のキャレット位置までスクロールするのではなく、全選択前の表示領域を維持する全選択アクションを作成します。

Source Code Examples

@Override public void selectAll() {
  Rectangle r = getVisibleRect();
  Document doc = getDocument();
  if (doc != null) {
    if (isEmacs) {
      setCaretPosition(doc.getLength());
      moveCaretPosition(0);
    } else { // Visual Studio Code
      setCaretPosition(0);
      moveCaretPosition(doc.getLength());
    }
  }
  EventQueue.invokeLater(() -> scrollRectToVisible(r));
}
View in GitHub: Java, Kotlin

Explanation

  • Default
    • デフォルトのJTextComponentselect-allアクションは全選択でCaretは全テキスト末尾に移動し、表示領域もその末尾までスクロールする
    • Apache NetBeansやメモ帳(notepad.exe)の動作と同じ
  • Override selectAll
    • JTextComponent#selectAll()、またはDefaultEditorKit#SelectAllActionをオーバーライドし、全選択前の表示領域を保存(JTextComponent#getVisibleRect())、全選択後にその領域を復元(EventQueue.invokeLater( () -> JTextComponent#scrollRectToVisible(r)))
    • JTextComponent#selectAll()メソッドとCtrl+Aで実行されるDefaultEditorKit#SelectAllActionはどちらも同じようにsetCaretPosition(0); moveCaretPosition(doc.getLength());を実行しているが、別々に実装されているので注意が必要
    • Visual Studio Codeなどと同様で全選択後のCaretは全テキスト末尾に移動するが、表示領域は移動しない
    • 選択状態でキー入力すると選択していた文字列の先頭にCaret移動するようInputMapActionMapを調節
  • move Caret top
    • Override selectAllと同様の表示領域を維持する処理に加えて、全選択後のCaret位置を全テキスト先頭に変更
    • GNU Emacsなどの動作と同じになる
    • 選択状態でキー入力すると選択していた文字列の末尾にCaret移動するようInputMapActionMapを調節

  • IntelliJ IDEAのように全選択でCaret位置を移動しないよう設定する方法は?

Reference

Comment