• title: JTabbedPaneの余白にJButtonを配置 tags: [JTabbedPane, OverlayLayout, JButton, UIManager] author: aterai pubdate: 2008-03-03T14:07:59+09:00 description: JTabbedPaneのタブエリアに余白を作成し、そこにOverlayLayoutを使ってJButtonを配置します。

概要

JTabbedPaneのタブエリアに余白を作成し、そこにOverlayLayoutを使ってJButtonを配置します。

サンプルコード

final JButton b = new ToolBarButton(icon);
b.addActionListener(new ActionListener() {
  @Override public void actionPerformed(ActionEvent e) {
    tabs.addTab("qwerqwer", new JLabel("yetyet"));
  }
});
tabs = new ClippedTitleTabbedPane() {
  @Override public void updateUI() {
    UIManager.put("TabbedPane.tabAreaInsets", null); //uninstall
    super.updateUI();
    setAlignmentX(Component.LEFT_ALIGNMENT);
    setAlignmentY(Component.TOP_ALIGNMENT);
    b.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
    setAlignmentX(Component.LEFT_ALIGNMENT);
    setAlignmentY(Component.TOP_ALIGNMENT);
    tabAreaInsets = getTabAreaInsets();
    UIManager.put("TabbedPane.tabAreaInsets",
                  getButtonPaddingTabAreaInsets(b, getTabInsets(), tabAreaInsets));
    super.updateUI();
  }
  private Insets tabAreaInsets = null;
};
JPanel p = new JPanel();
p.setLayout(new OverlayLayout(p));
p.add(button);
p.add(tabs);
View in GitHub: Java, Kotlin
//Insets ti = UIManager.getInsets("TabbedPane.tabInsets");
//Insets ai = UIManager.getInsets("TabbedPane.tabAreaInsets");
public Insets getButtonPaddingTabAreaInsets(JButton b, Insets ti, Insets ai) {
  FontMetrics fm = b.getFontMetrics(b.getFont());
  int tih = b.getPreferredSize().height - fm.getHeight() - ti.top - ti.bottom - ai.bottom;
  return new Insets(Math.max(ai.top, tih), b.getPreferredSize().width + ai.left, ai.bottom, ai.right);
}

解説

上記のサンプルは、タブブラウザ風の動作となるように設定しています。

  • タブエリアの左上にあるボタンをクリックするとタブが追加される
  • メニューからすべてのタブを削除する
  • タブエリアに余裕がある場合は80px、無い場合は(タブエリアの幅/タブ数)と、常にタブ幅は一定
    • 折り返しや、スクロールが発生するとレイアウトが崩れるため

コンポーネントの追加には、以下の方法を使用しています(比較:JTabbedPaneの余白にJCheckBoxを配置)。

  • ボタンの幅だけ、tabAreaInsetsの左余白を拡大する
  • OverlayLayoutで、JButtonJTabbedPane(上で作った余白に)を重ねて表示
    • このため、JTabbedPane.TOPにしか対応していない

参考リンク

コメント