---
category: swing
folder: NewTabButton
title: JTabbedPane風のタブ配置をレイアウトマネージャーで変更
tags: [CardLayout, LayoutManager, JRadioButton, JTabbedPane]
author: aterai
pubdate: 2009-06-08T13:05:45+09:00
description: CardLayoutとJRadioButtonで作成したJTabbedPane風コンポーネントのタブ配置を自作レイアウトマネージャーで変更します。
image: https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTQUU8wtpI/AAAAAAAAAfY/BJyG5weJ1VA/s800/NewTabButton.png
hreflang:
    href: https://java-swing-tips.blogspot.com/2009/06/new-tab-button.html
    lang: en
---
* 概要 [#summary]
`CardLayout`と`JRadioButton`で作成した`JTabbedPane`風コンポーネントのタブ配置を自作レイアウトマネージャーで変更します。

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

* サンプルコード [#sourcecode]
#code(link){{
class TabLayout implements LayoutManager, Serializable {
  private static final long serialVersionUID = 1L;
  private static final int TAB_WIDTH = 100;
  @Override public void addLayoutComponent(String name, Component comp) {
    /* not needed */
  }

  @Override public void removeLayoutComponent(Component comp) {
    /* not needed */
  }

  @Override public Dimension preferredLayoutSize(Container parent) {
    synchronized (parent.getTreeLock()) {
      Insets insets = parent.getInsets();
      int last = parent.getComponentCount() - 1;
      int w = 0;
      int 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()) {
      int ncomponents = parent.getComponentCount();
      if (ncomponents == 0) {
        return;
      }
      // int nrows = 1;
      // boolean ltr = parent.getComponentOrientation().isLeftToRight();
      Insets insets = parent.getInsets();
      int ncols = ncomponents - 1;
      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 > TAB_WIDTH * ncols ? TAB_WIDTH : width / ncols;
      int gap = width - w * ncols;
      int x = insets.left;
      int y = insets.top;
      for (int i = 0; i < ncomponents; i++) {
        int cw = i == ncols ? lastw : w + (gap-- > 0 ? 1 : 0);
        parent.getComponent(i).setBounds(x, y, cw, h);
        x += cw;
      }
    }
  }

  @Override public String toString() {
    return getClass().getName();
  }
}
}}

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

- 最後のタブ(タブ追加ボタン)の幅は常に固定
- 最後のタブの高さがタブエリアの高さ
- タブエリアの幅に余裕がある場合は各タブ幅は`100px`で一定
- タブエリアの幅に余裕がない場合は各タブ幅は均等
- タブを削除した場合先頭タブにフォーカスが移動する
- 左の`JButton`(ダミー)はタブエリアをラップする`JPanel(BorderLayout)`の`BorderLayout.WEST`に配置
- 左端に追加した`JButton`はタブエリアをラップする`JPanel(BorderLayout)`の`BorderLayout.WEST`で配置
- アイコンはランダム

* 参考リンク [#reference]
- [https://xp-style-icons.en.softonic.com/ XP Style Icons - Download]
- [[CardLayoutを使ってJTabbedPane風のコンポーネントを作成>Swing/CardLayoutTabbedPane]]

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

#comment