TITLE:JTabbedPane風のタブ配置をレイアウトマネージャーで変更
#navi(../)
#tags(CardLayout, LayoutManager, JRadioButton, JTabbedPane)
RIGHT:Posted by &author(aterai); at 2009-06-08
* JTabbedPane風のタブ配置をレイアウトマネージャーで変更 [#hc561759]
`CardLayout`と`JRadioButton`で作成した`JTabbedPane`風コンポーネントのタブ配置を自作レイアウトマネージャーで変更します。

#download
#ref(https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTQUU8wtpI/AAAAAAAAAfY/BJyG5weJ1VA/s800/NewTabButton.png)

** サンプルコード [#dbcd9376]
#code(link){{
class TabLayout implements LayoutManager, java.io.Serializable {
  @Override public void addLayoutComponent(String name, Component comp) {}
  @Override public void removeLayoutComponent(Component comp) {}
  @Override public Dimension preferredLayoutSize(Container parent) {
    synchronized (parent.getTreeLock()) {
      Insets insets = parent.getInsets();
      int last = parent.getComponentCount()-1;
      int w = 0, h = 0;
      if(last>=0) {
        Component comp = parent.getComponent(last);
        Dimension d = comp.getPreferredSize();
        w = d.width;
        h = d.height;
      }
      return new Dimension(insets.left + insets.right + w,
                           insets.top + insets.bottom + h);
    }
  }

  @Override public Dimension minimumLayoutSize(Container parent) {
    synchronized (parent.getTreeLock()) {
      return new Dimension(100, 24);
    }
  }

  @Override public void layoutContainer(Container parent) {
    synchronized (parent.getTreeLock()) {
      Insets insets = parent.getInsets();
      int ncomponents = parent.getComponentCount();
      int nrows = 1;
      int ncols = ncomponents-1;
      //boolean ltr = parent.getComponentOrientation().isLeftToRight();

      if (ncomponents == 0) {
        return;
      }
      int lastw = parent.getComponent(ncomponents-1).getPreferredSize().width;
      int width = parent.getWidth() - (insets.left + insets.right) - lastw;
      int h = parent.getHeight() - (insets.top + insets.bottom);
      int w = (width>100*(ncomponents-1))?100:width/ncols;
      int gap = width - w*ncols;
      int x = insets.left;
      int y = insets.top;
      for (int i=0;i<ncomponents;i++) {
        int a = (gap>0)?1:0;
        gap--;
        int cw = (i==ncols)?lastw:w+a;
        parent.getComponent(i).setBounds(x, y, cw, h);
        x += w + a;
      }
    }
  }
  @Override public String toString() {
    return getClass().getName();
  }
}
}}

** 解説 [#l2903531]
上記のサンプルでは、以下のような`LayoutManager`を作成して`JRadioButton`をタブ風に並べています。

- 最後のタブ(タブ追加ボタン)は常に幅固定
- 最後のタブの高さがタブエリアの高さ
- タブエリアの幅に余裕がある場合は、各タブ幅は`100px`で一定
- タブエリアの幅に余裕がない場合は、各タブ幅は均等

- その他
-- タブを削除した場合、先頭タブにフォーカスが移動する
-- 左の`JButton`(ダミー)は、タブエリアをラップする`JPanel(BorderLayout)`の`BorderLayout.WEST`に配置
-- アイコンはランダム

** 参考リンク [#rea3e94d]
- [http://www.icongalore.com/ XP Style Icons - Windows Application Icon, Software XP Icons]
- [[CardLayoutを使ってJTabbedPane風のコンポーネントを作成>Swing/CardLayoutTabbedPane]]

** コメント [#n5459406]
- タブをクリックした時ではなく、`mousePressed`で切り替えるように変更。 -- [[aterai]] &new{2012-03-21 (水) 18:46:30};

#comment