• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:TableCellEditorをスクロール可能にする
#navi(../)
#tags(JTable, JScrollPane, JTextArea, TableCellEditor, Focus)
RIGHT:Posted by &author(aterai); at 2011-06-20
* TableCellEditorをスクロール可能にする [#i988a941]
---
category: swing
folder: ScrollingCellEditor
title: TableCellEditorをスクロール可能にする
tags: [JTable, JScrollPane, JTextArea, TableCellEditor, Focus]
author: aterai
pubdate: 2011-06-20T14:39:55+09:00
description: JTableのTableCellEditorとして、JTextAreaとJScrollPaneを使用します。
image: https://lh4.googleusercontent.com/-DDRbJ9WhSJk/Tf7btYjUE7I/AAAAAAAAA9s/yVKIKC55zIw/s800/ScrollingCellEditor.png
---
* 概要 [#summary]
`JTable`の`TableCellEditor`として、`JTextArea`と`JScrollPane`を使用します。

#download
#ref(https://lh4.googleusercontent.com/-DDRbJ9WhSJk/Tf7btYjUE7I/AAAAAAAAA9s/yVKIKC55zIw/s800/ScrollingCellEditor.png)
#download(https://lh4.googleusercontent.com/-DDRbJ9WhSJk/Tf7btYjUE7I/AAAAAAAAA9s/yVKIKC55zIw/s800/ScrollingCellEditor.png)

** サンプルコード [#gf065aec]
* サンプルコード [#sourcecode]
#code(link){{
class TextAreaCellEditor extends JTextArea implements TableCellEditor {
  private final JScrollPane scroll;
  public TextAreaCellEditor() {
    scroll = new JScrollPane(this);
    setLineWrap(true);
    KeyStroke enter = KeyStroke.getKeyStroke(
        KeyEvent.VK_ENTER, InputEvent.CTRL_MASK);
    getInputMap(JComponent.WHEN_FOCUSED).put(enter, new AbstractAction() {
class TextAreaCellEditor extends AbstractCellEditor implements TableCellEditor {
  private static final String KEY = "Stop-Cell-Editing";
  private final JTextArea textArea = new JTextArea();
  private final JScrollPane scroll = new JScrollPane(textArea);

  protected TextAreaCellEditor() {
    super();
    scroll.setBorder(BorderFactory.createEmptyBorder());
    // scroll.setViewportBorder(BorderFactory.createEmptyBorder());

    textArea.setLineWrap(true);
    textArea.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4));

    int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
    // Java 10: int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx();
    KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, modifiers);
    textArea.getInputMap(JComponent.WHEN_FOCUSED).put(enter, KEY);
    textArea.getActionMap().put(KEY, new AbstractAction() {
      @Override public void actionPerformed(ActionEvent e) {
        stopCellEditing();
      }
    });
  }

  @Override public Object getCellEditorValue() {
    return getText();
    return textArea.getText();
  }

  @Override public Component getTableCellEditorComponent(
      JTable table, Object value, boolean isSelected, int row, int column) {
    setFont(table.getFont());
    setText((value!=null)?value.toString():"");
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        setCaretPosition(getText().length());
        requestFocusInWindow();
      }
        JTable table, Object value, boolean isSelected, int row, int column) {
    // System.out.println("getTableCellEditorComponent");
    textArea.setFont(table.getFont());
    textArea.setText(Objects.toString(value, ""));
    EventQueue.invokeLater(() -> {
      textArea.setCaretPosition(textArea.getText().length());
      textArea.requestFocusInWindow();
      System.out.println("invokeLater: getTableCellEditorComponent");
    });
    return scroll;
  }
  @Override public boolean isCellEditable(final EventObject e) {
    if(e instanceof MouseEvent) {
      return ((MouseEvent)e).getClickCount() >= 2;

  @Override public boolean isCellEditable(EventObject e) {
    if (e instanceof MouseEvent) {
      return ((MouseEvent) e).getClickCount() >= 2;
    }
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        if(e instanceof KeyEvent) {
          KeyEvent ke = (KeyEvent)e;
          char kc = ke.getKeyChar();
          if(Character.isUnicodeIdentifierStart(kc)) {
            setText(getText()+kc);
          }
    // System.out.println("isCellEditable");
    EventQueue.invokeLater(() -> {
      if (e instanceof KeyEvent) {
        KeyEvent ke = (KeyEvent) e;
        char kc = ke.getKeyChar();
        if (Character.isUnicodeIdentifierStart(kc)) {
          textArea.setText(textArea.getText() + kc);
          System.out.println("invokeLater: isCellEditable");
        }
      }
    });
    return true;
  }
//......
}
}}

** 解説 [#nc5d399e]
* 解説 [#explanation]
上記のサンプルでは、`0`列目にデフォルトの`TableCellEditor(JTextField)`、`1`列目に`JTextArea`を継承した`TableCellEditor`を設定しています。

- `TableCellEditor#isCellEditable`
- `TableCellEditor#isCellEditable(...)`
-- マウスのダブルクリックで編集開始
- `TableCellEditor#getTableCellEditorComponent`
-- `JTextArea`に現在表示されているセル文字列をコピーし、戻り値の`Component`として、`JScrollPane`を返す
- `TableCellEditor#isCellEditable`, `EventQueue.invokeLater`
- `TableCellEditor#getTableCellEditorComponent(...)`
-- `JTextArea`に現在表示されているセル文字列をコピーし、戻り値の`Component`として`JScrollPane`を返す
- `TableCellEditor#isCellEditable(...)`、`EventQueue.invokeLater(...)`
-- キー入力で編集開始した場合、その入力を`JTextArea`の文字列末尾に追加
- `TableCellEditor#getTableCellEditorComponent`, `EventQueue.invokeLater`
-- `JTextArea`にフォースを移動し、`JTextArea`のキャレットも文字列末尾に移動
-- [https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Character.html#isUnicodeIdentifierStart-char- Character#isUnicodeIdentifierStart(char) (Java Platform SE 8)]
- `TableCellEditor#getTableCellEditorComponent(...)`、`EventQueue.invokeLater(...)`
-- `JTextArea`にフォーカスを移動し`JTextArea`のキャレットも文字列末尾に移動

** 参考リンク [#wcd8d89d]
* 参考リンク [#reference]
- [[TableCellEditorのレイアウトを変更>Swing/CellEditorLayout]]
- [[JTableのセル幅で文字列を折り返し>Swing/TableCellRenderer]]

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