概要

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

サンプルコード

ClippedTitleTabbedPane tabs = new ClippedTitleTabbedPane() {
  @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
  }

  @Override public float getAlignmentX() {
    return LEFT_ALIGNMENT;
  }

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

  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);
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルは、JTabbedPaneでタブブラウザ風の動作を実現するために、以下のような設定を行っています。

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

  • JTabbedPaneの左端ではなく右端にJButtonを配置するサンプル
import java.awt.*;
import javax.swing.*;

public class TabbedPaneWithButtonTest {
  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"));

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

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

  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);
    });
  }
}

参考リンク

コメント