TITLE:JTabbedPaneの余白にJButtonを配置
Posted by terai at 2008-03-03

JTabbedPaneの余白にJButtonを配置

JTabbedPaneのタブエリアに余白を作成し、そこにOverlayLayoutを使ってJButtonを配置します。
  • category: swing folder: TabbedPaneWithButton title: JTabbedPaneの余白にJButtonを配置 tags: [JTabbedPane, OverlayLayout, JButton, UIManager] author: aterai pubdate: 2008-03-03T14:07:59+09:00 description: JTabbedPaneのタブエリアに余白を作成し、そこにOverlayLayoutを使ってJButtonを配置します。 image: https://lh5.googleusercontent.com/_9Z4BYR88imo/TQTUOdUT3wI/AAAAAAAAAls/N2JYE_Dcr_Y/s800/TabbedPaneWithButton.png

概要

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

#screenshot

サンプルコード

#spanend
#spanadd
ClippedTitleTabbedPane tabs = new ClippedTitleTabbedPane() {
#spanend
  @Override public void updateUI() {
    String key = "TabbedPane.tabAreaInsets";
    UIManager.put(key, null); // uninstall
    super.updateUI();
    // setAlignmentX(Component.LEFT_ALIGNMENT);
    // setAlignmentY(Component.TOP_ALIGNMENT);
    // System.out.println(button.getAlignmentY());
    // button.setAlignmentY(Component.TOP_ALIGNMENT);
    // System.out.println(button.getAlignmentY());
    UIManager.put(key, getButtonPaddingTabAreaInsets());
    super.updateUI(); // reinstall
  }

#spandel
**サンプルコード [#l9d78f5a]
#spanend
#spandel
#code{{
#spanend
#spandel
JPanel p = new JPanel();
#spanend
#spandel
p.setLayout(new OverlayLayout(p));
#spanend
#spandel
button.setAlignmentX(0.0f);
#spanend
#spandel
button.setAlignmentY(0.0f);
#spanend
#spandel
tabPane.setAlignmentX(0.0f);
#spanend
#spandel
tabPane.setAlignmentY(0.0f);
#spanend
#spandel
p.add(button);
#spanend
#spandel
p.add(tabPane);
#spanend
  @Override public float getAlignmentX() {
    return LEFT_ALIGNMENT;
  }
#spanadd

#spanend
  @Override public float getAlignmentY() {
    return TOP_ALIGNMENT;
  }
#spanadd

#spanend
  private Insets getButtonPaddingTabAreaInsets() {
    Insets ti = getTabInsets();
    Insets ai = getTabAreaInsets();
    Dimension d = button.getPreferredSize();
    FontMetrics fm = getFontMetrics(getFont());
    int tih = d.height - fm.getHeight()
              - ti.top - ti.bottom - ai.bottom;
    return new Insets(
      Math.max(ai.top, tih),
      d.width + ai.left,
      ai.bottom,
      ai.right);
  }
#spanadd
}
#spanend
View in GitHub: Java, Kotlin

解説

上記のサンプルは、JTabbedPaneでタブブラウザ風の動作を実現するために、以下のような設定を行っています。
  • タブエリアの左上にあるボタンをクリックするとタブが追加する
  • メニューからすべてのタブを削除する
  • タブエリアに余裕がある場合は80px、無い場合は(タブエリアの幅/タブ数)と常にタブ幅は一定
    • 折り返しやスクロールが発生するとレイアウトが崩れることを防ぐための設定
  • -
  • JTabbedPaneの左端ではなく右端にJButtonを配置するサンプル
#spandel
public InsetsUIResource getButtonPaddingTabAreaInsets(JButton b) {
#spanend
  int bw = b.getPreferredSize().width;
  int bh = b.getPreferredSize().height;
  Insets insets = UIManager.getInsets("TabbedPane.tabInsets");
  Insets ti = (insets!=null)?insets:new Insets(0,0,0,0);
  insets = UIManager.getInsets("TabbedPane.tabAreaInsets");
  Insets ai = (insets!=null)?insets:new Insets(0,0,0,0);
  FontMetrics metrics = getFontMetrics(getFont());
  int tih = bh - metrics.getHeight()-ti.top-ti.bottom-ai.bottom;
  return new InsetsUIResource(Math.max(ai.top, tih), bw+ai.left, ai.bottom, ai.right);
#spanadd
import java.awt.*;
#spanend
#spanadd
import javax.swing.*;
#spanend
#spanadd

#spanend
#spanadd
public class TabbedPaneWithButtonTest {
#spanend
  public Component makeUI() {
    JTabbedPane tabs = new JTabbedPane();
    tabs.setAlignmentX(Component.RIGHT_ALIGNMENT);
    tabs.setAlignmentY(Component.TOP_ALIGNMENT);
    tabs.addTab("Tab 1", new JLabel("1"));
    tabs.addTab("Tab 2", new JLabel("2"));
#spanadd

#spanend
    JButton button = new JButton("https://ateraimemo.com/");
    button.setAlignmentX(Component.RIGHT_ALIGNMENT);
    button.setAlignmentY(Component.TOP_ALIGNMENT);
#spanadd

#spanend
    JPanel p = new JPanel();
    p.setLayout(new OverlayLayout(p));
    p.add(button);
    p.add(tabs);
    return p;
  }
#spanadd

#spanend
  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      } catch (Exception ex) {
        throw new IllegalArgumentException(ex);
      }
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new TabbedPaneWithButtonTest().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

解説

上記のサンプルは、以下のような動作*1の仕様になっています。
  • タブエリアの左上にあるボタンをクリックするとタブが追加される
  • メニューからすべてのタブを削除する
  • タブエリアに余裕がある場合は80pt、無い場合は(タブエリアの幅/タブ数)と、常にタブ幅は一定
    • 折り返しや、スクロールが発生するとレイアウトが崩れるため

参考リンク

コンポーネントの追加には、以下の方法を使用しています(比較:JTabbedPaneの余白にJCheckBoxを配置)。
  • ボタンの幅だけ、tabAreaInsets の左余白を拡大する
  • OverlayLayout で、JButtonとJTabbedPane(上で作った余白に)を重ねて表示
    • このため、JTabbedPane.TOP にしか対応していない

参考リンク

コメント

コメント