概要

NimbusLookAndFeelにおけるJTabbedPaneのタブ、タブエリアなどのスタイルを変更します。

サンプルコード

private static void configureUI() {
  UIDefaults d = UIManager.getLookAndFeelDefaults();
  d.put("TabbedPane:TabbedPaneContent.contentMargins", new Insets(0, 5, 5, 5));
  //d.put("TabbedPane:TabbedPaneTab.contentMargins",     new Insets(2, 8, 3, 8));
  //d.put("TabbedPane:TabbedPaneTabArea.contentMargins", new Insets(3, 10, 4, 10));
  d.put("TabbedPane:TabbedPaneTabArea.contentMargins", new Insets(3, 10, OVERPAINT, 10));

  Painter<JComponent> tabAreaPainter = new TabAreaPainter();
  d.put("TabbedPane:TabbedPaneTabArea[Disabled].backgroundPainter",          tabAreaPainter);
  d.put("TabbedPane:TabbedPaneTabArea[Enabled].backgroundPainter",           tabAreaPainter);
  d.put("TabbedPane:TabbedPaneTabArea[Enabled+MouseOver].backgroundPainter", tabAreaPainter);
  d.put("TabbedPane:TabbedPaneTabArea[Enabled+Pressed].backgroundPainter",   tabAreaPainter);

  d.put("TabbedPane:TabbedPaneContent.backgroundPainter", new TabContentPainter());

  Painter<JComponent> tabPainter = new TabPainter(false);
  d.put("TabbedPane:TabbedPaneTab[Enabled+MouseOver].backgroundPainter", tabPainter);
  d.put("TabbedPane:TabbedPaneTab[Enabled+Pressed].backgroundPainter",   tabPainter);
  d.put("TabbedPane:TabbedPaneTab[Enabled].backgroundPainter",           tabPainter);

  Painter<JComponent> selectedTabPainter = new TabPainter(true);
  d.put("TabbedPane:TabbedPaneTab[Focused+MouseOver+Selected].backgroundPainter", selectedTabPainter);
  d.put("TabbedPane:TabbedPaneTab[Focused+Pressed+Selected].backgroundPainter",   selectedTabPainter);
  d.put("TabbedPane:TabbedPaneTab[Focused+Selected].backgroundPainter",           selectedTabPainter);
  d.put("TabbedPane:TabbedPaneTab[MouseOver+Selected].backgroundPainter",         selectedTabPainter);
  d.put("TabbedPane:TabbedPaneTab[Selected].backgroundPainter",                   selectedTabPainter);
  d.put("TabbedPane:TabbedPaneTab[Pressed+Selected].backgroundPainter",           selectedTabPainter);
}
public static void createAndShowGUI() {
  try {
    for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
      if ("Nimbus".equals(laf.getName())) {
        UIManager.setLookAndFeel(laf.getClassName());
        configureUI();
      }
    }
  } catch (ClassNotFoundException | InstantiationException
             | IllegalAccessException | UnsupportedLookAndFeelException ex) {
    ex.printStackTrace();
  }
  JFrame frame = new JFrame("@title@");
  frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
  frame.getContentPane().add(new MainPanel());
  frame.pack();
  frame.setLocationRelativeTo(null);
  frame.setVisible(true);
}
private static class TabPainter implements Painter<JComponent> {
  private final Color color;
  private final boolean selected;
  protected TabPainter(boolean selected) {
    this.selected = selected;
    this.color = selected ? Color.WHITE : Color.ORANGE;
  }
  @Override public void paint(Graphics2D g, JComponent c, int width, int height) {
    int a = selected ? OVERPAINT : 0;
    int r = 6;
    int x = 3;
    int y = 3;
    Graphics2D g2 = (Graphics2D) g.create(0, 0, width, height + a);
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    int w = width - r - 1;
    int h = height + r;
    for (int i = 0; i < x; i++) {
      g2.setColor(new Color(0, 0, 0, 20));
      g2.fill(new RoundRectangle2D.Double(x - i, y - i, w + i + i, h, r, r));
    }
    g2.setColor(color);
    g2.fill(new RoundRectangle2D.Double(x, y, w, h + OVERPAINT, r, r));
    if (selected) {
      g2.setColor(Color.GREEN);
      g2.fill(new Rectangle2D.Double(0, height + STROKE_SIZE, width, OVERPAINT));
    }
    g2.dispose();
  }
}
private static class TabAreaPainter implements Painter<JComponent> {
  @Override public void paint(Graphics2D g, JComponent c, int w, int h) {
    Graphics2D g2 = (Graphics2D) g.create(0, 0, w, h);
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    RoundRectangle2D r = new RoundRectangle2D.Double(
      0, h - OVERPAINT,
      w - STROKE_SIZE,
      h - STROKE_SIZE,
      ARC, ARC);

    g2.setPaint(Color.WHITE);
    g2.fill(r);
    g2.setColor(Color.RED);
    g2.setStroke(new BasicStroke(STROKE_SIZE));
    g2.draw(r);
    g2.dispose();
  }
}
private static class TabContentPainter implements Painter<JComponent> {
  @Override public void paint(Graphics2D g, JComponent c, int w, int h) {
    Graphics2D g2 = (Graphics2D) g.create(0, 0, w, h);
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2.translate(0, -OVERPAINT);

    RoundRectangle2D r = new RoundRectangle2D.Double(
      0, 0,
      w - STROKE_SIZE,
      h - STROKE_SIZE + OVERPAINT,
      ARC, ARC);

    g2.setPaint(Color.WHITE);
    g2.fill(r);
    g2.setColor(Color.ORANGE);
    g2.setStroke(new BasicStroke(STROKE_SIZE));
    g2.draw(r);
    g2.dispose();
  }
}
view all

解説

上記のサンプルでは、NimbusLookAndFeelUIDefaultsにタブ、タブ領域、コンテンツ領域などを描画する独自の縁や背景色のPainterを設定するテストを行っています。選択タブのColor.GREEN、タブ領域のColor.CYANをコンテンツ領域と同じColor.WHITEに変更すると、選択タブとコンテンツ領域が一体になったスタイルを作成することができます。

  • TabbedPaneTabArea
    • タブを配置するエリアで、このサンプルでは下部背景をColor.CYAN、下部縁をColor.REDで描画するPainterを設定
      • 下部の領域は、タブエリア下部の高さOVERPAINTで、TabbedPane:TabbedPaneTabArea.contentMarginsbottomと同じに設定
      • 縁は上辺のみラウンド表示されるようにRoundRectangle2Dをクリップ
    • 一番最初に描画される
  • TabbedPaneContent
    • コンテンツを配置するエリアで、このサンプルでは背景をColor.WHITE、縁をColor.ORANGEで描画するPainterを設定
      • 縁は下辺のみラウンド表示されるようにRoundRectangle2Dをクリップ
    • 一番最後に描画される
  • TabbedPaneTab
    • タブを描画するPainterを設定
    • 選択されたタブを描画する場合は、クリップ領域の高さをOVERPAINTだけ拡大(タブエリアの下部を上書き)
      • 縁に影を設定し、タブエリアの下部にはみ出す部分は、Color.GREENの矩形で塗り潰している

参考リンク

コメント