TITLE:JTabbedPaneのタイトルをクリップ

JTabbedPaneのタイトルをクリップ

編集者:Terai Atsuhiro
作成日:2007-10-08
更新日:2021-09-19 (日) 10:50:33

概要

JDK 6 で導入されたタブにコンポーネントを追加する機能を使って、長いタイトルのタブは文字列をクリップして表示します。

#screenshot

サンプルコード

class ClippedTitleTabbedPane extends JTabbedPane {
  private final Insets tabInsets = getTabInsets();
  private final Insets tabAreaInsets = getTabAreaInsets();
  public ClippedTitleTabbedPane() {
    super();
    addComponentListener(new ComponentAdapter() {
      @Override public void componentResized(ComponentEvent e) {
        initTabWidth();
      }
    });
    addChangeListener(new ChangeListener() {
      @Override public void stateChanged(ChangeEvent e) {
        initTabWidth();
      }
    });
  }
  private Insets getTabInsets() {
    Insets i = UIManager.getInsets("TabbedPane.tabInsets");
    if(i!=null) {
      return i;
    }else{
      SynthStyle style = SynthLookAndFeel.getStyle(this, Region.TABBED_PANE_TAB);
      SynthContext context = new SynthContext(
        this, Region.TABBED_PANE_TAB, style, SynthConstants.ENABLED);
      return style.getInsets(context, null);
    }
  }
  private Insets getTabAreaInsets() {
    Insets i = UIManager.getInsets("TabbedPane.tabAreaInsets");
    if(i!=null) {
      return i;
    }else{
      SynthStyle style = SynthLookAndFeel.getStyle(this, Region.TABBED_PANE_TAB_AREA);
      SynthContext context = new SynthContext(
        this, Region.TABBED_PANE_TAB_AREA, style, SynthConstants.ENABLED);
      return style.getInsets(context, null);
    }
  }
  @Override
  public void insertTab(String title, Icon icon, Component component,
                        String tip, int index) {
    super.insertTab(title, icon, component, tip==null?title:tip, index);
    JLabel label = new JLabel(title, JLabel.CENTER);
    Dimension dim = label.getPreferredSize();
    label.setPreferredSize(new Dimension(0, dim.height+tabInsets.top+tabInsets.bottom));
    setTabComponentAt(index, label);
    initTabWidth();
  }
  public void initTabWidth() {
    Insets insets = getInsets();
    int areaWidth = getWidth() - tabAreaInsets.left - tabAreaInsets.right
                               - insets.left - insets.right;
    int tabCount  = getTabCount();
    int tabWidth  = 0; // = tabInsets.left + tabInsets.right + 3;
    int gap     = 0;
    switch(getTabPlacement()) {
      case LEFT: case RIGHT:
      tabWidth = areaWidth/4;
      gap = 0;
      break;
      case BOTTOM: case TOP: default:
      tabWidth = areaWidth/tabCount;
      gap = areaWidth - (tabWidth * tabCount); //System.out.println(gap);
    }
    // "3" @see BasicTabbedPaneUI#calculateTabWidth
    tabWidth = tabWidth - tabInsets.left - tabInsets.right - 3;
    for(int i=0;i<tabCount;i++) {
      JLabel l = (JLabel)getTabComponentAt(i);
      if(l==null) break;
      l.setPreferredSize(new Dimension(tabWidth+(i<gap?1:0),
                                       l.getPreferredSize().height));
    }
    revalidate();
  }
}
  • &jnlp;
  • &jar;
  • &zip;

解説

下のJTabbedPaneでは、タブにJTabbedPane#setTabComponentAtメソッドを使ってJLabelを追加し、そのクリップ機能を利用して長いタイトル文字列をクリップしています。

JTabbedPaneのタブを等幅にしてタイトルをクリップと、ほぼ同等*1ですが、TabbedPaneUI#paintTextで文字列の描画をオーバーライドする必要も無く、ソースも短くて実装が簡単です。

参考リンク

コメント

  • 以下の二点を変更しました: tabAreaInsetsを考慮するように修正、TOP-LEFTの切り替えの追加 -- terai
  • Synthに仮?対応 -- terai