• category: swing folder: EditTabTitle title: JTabbedPaneのタブタイトルを変更 tags: [JTabbedPane, GlassPane, JTextField] author: aterai pubdate: 2006-03-27T01:01:49+09:00 description: JTabbedPaneのタブタイトルを直接編集します。 image: https://lh5.googleusercontent.com/_9Z4BYR88imo/TQTMGR-jIQI/AAAAAAAAAYo/g3tGLp5zrdY/s800/EditTabTitle.png hreflang:
       href: http://java-swing-tips.blogspot.com/2008/09/double-click-on-each-tab-and-change-its.html
       lang: en

概要

JTabbedPaneのタブタイトルを直接編集します。

サンプルコード

class EditableTabbedPane extends JTabbedPane {
  private final JComponent glassPane = new EditorGlassPane();
  private final JTextField editor = new JTextField();
  private final Action startEditing = new AbstractAction() {
    @Override public void actionPerformed(ActionEvent e) {
      getRootPane().setGlassPane(glassPane);
      Rectangle rect = getBoundsAt(getSelectedIndex());
      Point p = SwingUtilities.convertPoint(
          EditableTabbedPane.this, rect.getLocation(), glassPane);
      //rect.setBounds(p.x + 2, p.y + 2, rect.width - 4, rect.height - 4);
      rect.setLocation(p);
      rect.grow(-2, -2);
      editor.setBounds(rect);
      editor.setText(getTitleAt(getSelectedIndex()));
      editor.selectAll();
      glassPane.add(editor);
      glassPane.setVisible(true);
      editor.requestFocusInWindow();
    }
  };
  private final Action cancelEditing = new AbstractAction() {
    @Override public void actionPerformed(ActionEvent e) {
      glassPane.setVisible(false);
    }
  };
  private final Action renameTab = new AbstractAction() {
    @Override public void actionPerformed(ActionEvent e) {
      if (!editor.getText().trim().isEmpty()) {
        setTitleAt(getSelectedIndex(), editor.getText());
        //java 1.6.0 ---->
        Component c = getTabComponentAt(getSelectedIndex());
        if (c instanceof JComponent) {
          ((JComponent) c).revalidate();
        }
        //<----
      }
      glassPane.setVisible(false);
    }
  };
  protected EditableTabbedPane() {
    super();
    editor.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
    editor.getInputMap(JComponent.WHEN_FOCUSED).put(
        KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "rename-tab");
    editor.getActionMap().put("rename-tab", renameTab);
    editor.getInputMap(JComponent.WHEN_FOCUSED).put(
        KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel-editing");
    editor.getActionMap().put("cancel-editing", cancelEditing);

    addMouseListener(new MouseAdapter() {
      @Override public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 2) {
          startEditing.actionPerformed(null);
        }
      }
    });
    getInputMap(JComponent.WHEN_FOCUSED).put(
        KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "start-editing");
    getActionMap().put("start-editing", startEditing);
  }
  private class EditorGlassPane extends JComponent {
    protected EditorGlassPane() {
      super();
      setOpaque(false);
      setFocusTraversalPolicy(new DefaultFocusTraversalPolicy() {
        @Override public boolean accept(Component c) {
          return Objects.equals(c, editor);
        }
      });
      addMouseListener(new MouseAdapter() {
        @Override public void mouseClicked(MouseEvent e) {
          //if (Objects.nonNull(rect) && !rect.contains(e.getPoint())) {
          if (!editor.getBounds().contains(e.getPoint())) {
            renameTab.actionPerformed(null);
          }
        }
      });
    }
    @Override public void setVisible(boolean flag) {
      super.setVisible(flag);
      setFocusTraversalPolicyProvider(flag);
      setFocusCycleRoot(flag);
    }
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、JTabbedPaneのタブタイトルをExcelなどのように直接編集できるよう設定しています。

編集が開始されると、対象となるタブ上にJTextFieldをレイアウトしたGlassPaneを表示しています。このGlassPaneには、編集中はフォーカスの移動が起こらないようにするためのFocusTraversalPolicyなどを追加しています。

  • 操作方法
    • マウスでタブをダブルクリック、またはタブを選択してEnterキーで編集開始
    • 編集中に入力欄以外をクリック、またはEnterキーでタイトル文字列が確定
    • 編集中はTabキーを押しても無視
    • Escキーで編集をキャンセル
    • 0文字で確定した場合も、キャンセル扱い

参考リンク

コメント