---
category: swing
folder: TextComponentMouseListener
title: JTextAreaをマウスで長押しして単語選択などを実行する
tags: [JTextArea, MouseListener, DefaultEditorKit]
tags: [JTextArea, MouseListener, DefaultEditorKit, JTextComponent]
author: aterai
pubdate: 2023-06-12T00:32:36+09:00
description: JTextAreaにMouseListenerを追加し、マウス左ボタンの長押しで単語選択、右クリックでのフォーカス移動などの機能を追加します。
image: https://drive.google.com/uc?id=1F3ifdFQfWTnhHiZrEL5ScH5MD8wDXc9i
---
* 概要 [#summary]
JTextAreaにMouseListenerを追加し、マウス左ボタンの長押しで単語選択、右クリックでのフォーカス移動などの機能を追加します。
`JTextArea`に`MouseListener`を追加し、マウス左ボタンの長押しで単語選択、右クリックでのフォーカス移動などの機能を追加します。

#download(https://drive.google.com/uc?id=1F3ifdFQfWTnhHiZrEL5ScH5MD8wDXc9i)

* サンプルコード [#sourcecode]
#code(link){{
class TextComponentMouseHandler extends MouseAdapter {
  private final AtomicInteger count = new AtomicInteger(0);
  private final Timer holdTimer = new Timer(1000, null);
  private final List<String> list = Arrays.asList(
      DefaultEditorKit.selectWordAction,
      DefaultEditorKit.selectLineAction,
      DefaultEditorKit.selectParagraphAction,
      DefaultEditorKit.selectAllAction);

  protected TextComponentMouseHandler(JTextComponent textArea) {
    super();
    holdTimer.setInitialDelay(500);
    holdTimer.addActionListener(e -> {
      Timer timer = (Timer) e.getSource();
      if (timer.isRunning()) {
        int i = count.getAndIncrement();
        if (i < list.size()) {
          String cmd = list.get(i);
          textArea.getActionMap().get(cmd).actionPerformed(e);
        } else {
          timer.stop();
          count.set(0);
        }
      }
    });
  }

  @Override public void mousePressed(MouseEvent e) {
    boolean isSingleClick = e.getClickCount() == 1;
    if (isSingleClick) {
      JTextComponent textArea = (JTextComponent) e.getComponent();
      if (!textArea.hasFocus()) {
        textArea.requestFocusInWindow();
      }
      if (textArea.getSelectedText() == null) {
        // Java 9: int pos = textArea.viewToModel2D(e.getPoint());
        int pos = textArea.viewToModel(e.getPoint());
        textArea.setCaretPosition(pos);
      }
      if (e.getButton() == MouseEvent.BUTTON1) {
        holdTimer.start();
      }
    }
  }

  @Override public void mouseReleased(MouseEvent e) {
    holdTimer.stop();
    count.set(0);
  }

  @Override public void mouseDragged(MouseEvent e) {
    mouseReleased(e);
  }
}
}}

* 解説 [#explanation]
- マウス左ボタンの長押し
-- `1.5`秒後に`getActionMap().get(DefaultEditorKit.selectWordAction)`アクションを実行して単語選択
-- 左ボタンの長押しが継続している場合は`2.5`秒後に`getActionMap().get(DefaultEditorKit.selectLineAction)`アクションを実行して行選択
-- `3.5`秒後に`getActionMap().get(DefaultEditorKit.selectParagraphAction)`アクションを実行してパラグラフ選択
-- `4.5`秒後に`getActionMap().get(DefaultEditorKit.selectAllAction)`アクションを実行して全選択
-- 以降はタイマーをストップ
- `MouseListener#mousePressed(...)`をオーバーライド
-- シングルクリック、かつ`JTextArea`にフォーカスが存在しない場合は右、中ボタンでも`JTextArea#requestFocusInWindow()`を実行してフォーカスを取得
--- また文字列選択されていない場合は右、中ボタンでもキャレットをクリック位置に移動
-- 左ボタンのシングルクリックの場合は長押しのタイマーを起動
-- デフォルトのダブルクリックには単語選択が割り当てられているのでこれに干渉しないよう注意が必要
- `MouseListener#mouseReleased(...)`、`MouseMotionListener#mouseDragged(...)`をオーバーライド
-- 長押しのタイマーを停止、リセット

* 参考リンク [#reference]
- [[JTextArea内の文字列がマウス操作で選択されたら自動的にコピーする>Swing/CopyOnSelect]]
- [[JTextAreaで単語選択を実行した場合の区切り文字を変更する>Swing/SelectWordAction]]
- [[JPopupMenuをボタンの長押しで表示>Swing/PressAndHoldButton]]

* コメント [#comment]
#comment
#comment