• category: swing folder: CellEditorLayout title: TableCellEditorのレイアウトを変更 tags: [JTable, TableCellEditor, BorderLayout, JTextField, JButton, Focus, KeyboardFocusManager] author: aterai pubdate: 2009-02-02T14:08:34+09:00 description: TableCellEditorのレイアウトを変更して、CellEditorの隣にJButtonを配置します。 image: https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTIlcF-6vI/AAAAAAAAATA/mS6Q_BfuY6c/s800/CellEditorLayout.png

概要

TableCellEditorのレイアウトを変更して、CellEditorの隣にJButtonを配置します。

サンプルコード

class CustomComponentCellEditor extends DefaultCellEditor {
  protected final JTextField field;
  protected JButton button;
  private final JPanel panel = new JPanel(new BorderLayout());

  public CustomComponentCellEditor(JTextField field) {
    super(field);
    this.field = field;
    button = new JButton();
    button.setPreferredSize(new Dimension(25, 0));
    field.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
    panel.add(field);
    panel.add(button, BorderLayout.EAST);
    panel.setFocusable(false);
  }

  @Override public Component getTableCellEditorComponent(JTable table, Object value,
                         boolean isSelected, int row, int column) {
    // System.out.println("getTableCellEditorComponent");
    field.setText(Objects.toString(value, ""));
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        field.requestFocusInWindow();
      }
    });
    return panel;
  }

  @Override public boolean isCellEditable(final EventObject e) {
    //System.out.println("isCellEditable");
    if (e instanceof KeyEvent) {
      // System.out.println("KeyEvent");
      EventQueue.invokeLater(new Runnable() {
        @Override public void run() {
          char kc = ((KeyEvent) e).getKeyChar();
          if (!Character.isIdentifierIgnorable(kc)) {
            field.setText(field.getText() + kc);
          }
          field.setCaretPosition(field.getText().length());
          // field.requestFocusInWindow();
        }
      });
    }
    return super.isCellEditable(e);
  }

  @Override public Component getComponent() {
    return panel;
  }
}
View in GitHub: Java, Kotlin

解説

  • 0列目
    • DefaultCellEditorを継承するCustomComponentCellEditorを作成
    • JTextFieldをコンストラクタの引数にしているがダミー
    • 実体はJPanelで、これをセルエディタとして表示(TableCellEditor#getTableCellEditorComponentJPanelを返す)
    • このJPanelのレイアウトをBorderLayoutにしてJTextFieldJButtonを配置
    • TableCellEditor#getCellEditorValueJTextFieldの値を返し、フォーカス、キー入力時の編集開始などもJTextFieldになるように変更
    • 参考: Swing - JTable editor issueの、Darryl.Burke さんの投稿(2009/01/27 20:12 (reply 6 of 8))
  • 1列目
    • DefaultCellEditorを継承するCustomCellEditorを作成
    • JTextFieldをコンストラクタの引数(セルエディタの実体)として使用
    • JTextFieldJButtonの幅の右余白を設定
    • JTextFieldが表示されたときに、余白にJButtonsetBoundsで配置
    • 参考: JTextField内にアイコンを追加
class CustomCellEditor extends DefaultCellEditor {
  private static final int BUTTON_WIDTH = 20;
  protected final JButton button = new JButton();

  public CustomCellEditor(final JTextField field) {
    super(field);
    field.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, BUTTON_WIDTH));
    field.addHierarchyListener(new HierarchyListener() {
      @Override public void hierarchyChanged(HierarchyEvent e) {
        if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0
            && field.isShowing()) {
          field.removeAll();
          field.add(button);
          Rectangle r = field.getBounds();
          button.setBounds(r.width - BUTTON_WIDTH, 0, BUTTON_WIDTH, r.height);
        }
      }
    });
  }

  @Override public Component getComponent() {
    // @see JTable#updateUI()
    SwingUtilities.updateComponentTreeUI(button);
    return super.getComponent();
  }
}
  • 2列目
    • DefaultCellEditorを継承するCustomComponentCellEditor2を作成
      • JTextFieldDefaultCellEditorのコンストラクタの引数にしているが、ダミーで使用しない
    • 実体はJPanelを継承するCustomComponentで、これをセルエディタとして表示
    • CustomComponent#processKeyBinding(...)をオーバーライドして、キー入力開始時にKeyboardFocusManager.getCurrentKeyboardFocusManager().redispatchEvent(field, e);を呼び出している
    • あとは、0列目のCustomComponentCellEditorと同様
class CustomComponent extends JPanel {
  public final JTextField field = new JTextField();
  protected JButton button;
  public CustomComponent() {
    super(new BorderLayout(0, 0));
    button = new JButton();
    this.add(field);
    this.add(button, BorderLayout.EAST);
  }
  @Override protected boolean processKeyBinding(
      final KeyStroke ks, final KeyEvent e, int condition, boolean pressed) {
    if (!field.isFocusOwner() && !pressed) {
      field.requestFocusInWindow();
      EventQueue.invokeLater(new Runnable() {
        @Override public void run() {
          KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .redispatchEvent(field, e);
        }
      });
    }
    return super.processKeyBinding(ks, e, condition, pressed);
  }
}
class CustomComponentCellEditor2 extends DefaultCellEditor {
  private final CustomComponent component;
  public CustomComponentCellEditor2(CustomComponent component) {
    super(component.field);
    this.component = component;
  }
  @Override public Component getTableCellEditorComponent(JTable table,
        Object value, boolean isSelected, int row, int column) {
    component.field.setText(value != null ? value.toString() : "");
    return component;
  }
  @Override public Component getComponent() {
    return component;
  }
}
  • 3列目
    • デフォルト

参考リンク

コメント