概要

JTabbedPaneのタブコンポーネントにアイコンを設定したJLabelを使用し、タブが選択された場合そのタイトルを追加表示します。

スクリーンショット

Swing/SelectedTabTitleText.png

サンプルコード

tabs.addChangeListener(e -> {
  JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
  if (tabbedPane.getTabCount() <= 0) {
    return;
  }
  int idx = tabbedPane.getSelectedIndex();
  for (int i = 0; i < tabbedPane.getTabCount(); i++) {
    Component c = tabbedPane.getTabComponentAt(i);
    if (c instanceof JLabel) {
      ((JLabel) c).setText(i == idx ? tabbedPane.getTitleAt(i) : null);
    }
  }
});

// ...
private static void addTab(JTabbedPane tabbedPane, TabTitle tt, Component c) {
  tabbedPane.addTab(tt.title, c);
  URL url = tt.url;
  Icon icon = Objects.nonNull(url) ? new ImageIcon(url) : UIManager.getIcon("html.missingImage");
  JLabel label = new JLabel(null, icon, SwingConstants.CENTER) {
    @Override public Dimension getPreferredSize() {
      Dimension d = super.getPreferredSize();
      Container c = SwingUtilities.getAncestorOfClass(JTabbedPane.class, this);
      if (c instanceof JTabbedPane) {
        int tp = ((JTabbedPane) c).getTabPlacement();
        if (tp == TOP || tp == BOTTOM) {
          d.height = icon.getIconHeight() + tabbedPane.getFont().getSize() + getIconTextGap();
        }
      }
      return d;
    }
  };
  label.setVerticalTextPosition(SwingConstants.BOTTOM);
  label.setHorizontalTextPosition(SwingConstants.CENTER);
  tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, label);
}
View in GitHub: Java, Kotlin

解説

  • JTabbedPaneで選択されているタブの幅のみ拡張すると同様に、JTabbedPaneChangeListenerを追加してタブ選択が変更されたらタブコンポーネントを更新しているが、このサンプルでは推奨サイズを変更してタブタイトルを非表示にするのではなくJLabel#setText(null)でタブタイトルを非表示にしている
    • JTabbedPaneの各タブには表示に使用するタブコンポーネントとは別にタブタイトルが保存可能なので、タブ選択時にタブタイトルを復元する場合はこれをJTabbedPane#getTitleAt(index)で取得してタブコンポーネントのJLabelsetText(title)で適用している
  • タブコンポーネントとして使用するJLabellabel.setVerticalTextPosition(SwingConstants.BOTTOM)label.setHorizontalTextPosition(SwingConstants.CENTER)でアイコンの下にタイトルを表示するためタイトルの表示・非表示でその高さが変化するが、タブ自体の高さは選択で変更せずにアイコンの高さ、タイトル文字列の高さ、JLabel#getIconTextGap()の合計を固定値として使用
  • 起動時に先頭タブを選択状態にしてタブタイトルも表示するため、一旦JTabbedPane.setSelectedIndex(-1)でタブ選択を解除してからEventQueue.invokeLater( () -> tabbedPane.setSelectedIndex(0) )であとから選択し直している
    • JTabbedPane.setSelectedIndex(0)だけ実行してもすでに先頭の0番目タグが選択状態なのでChangeListenerのイベントが発生しない

参考リンク

コメント