概要

TitledBorderMatteBorderを使用してTitle付きのSeparatorを作成します。

サンプルコード

class TitledSeparator extends JLabel {
  private final String title;
  private final Color target;
  private final int height;
  private final int titlePosition;

  public TitledSeparator(String title, int height, int titlePosition) {
    this(title, null, height, titlePosition);
  }

  public TitledSeparator(
      String title, Color target, int height, int titlePosition) {
    super();
    this.title = title;
    this.target = target;
    this.height = height;
    this.titlePosition = titlePosition;
    updateBorder();
  }

  private void updateBorder() {
    Icon icon = new TitledSeparatorIcon();
    setBorder(BorderFactory.createTitledBorder(
        BorderFactory.createMatteBorder(height, 0, 0, 0, icon), title,
        TitledBorder.DEFAULT_JUSTIFICATION, titlePosition));
  }

  @Override public Dimension getMaximumSize() {
    Dimension d = super.getPreferredSize();
    d.width = Short.MAX_VALUE;
    return d;
  }

  @Override public void updateUI() {
    super.updateUI();
    EventQueue.invokeLater(this::updateBorder);
  }

  private class TitledSeparatorIcon implements Icon {
    private int width = -1;
    private Paint painter1;
    private Paint painter2;

    @Override public void paintIcon(Component c, Graphics g, int x, int y) {
      int w = c.getWidth();
      if (w != width || painter1 == null || painter2 == null) {
        width = w;
        Point2D start = new Point2D.Float();
        Point2D end = new Point2D.Float(width, 0);
        float[] dist = {0f, 1f};
        Color ec = Optional.ofNullable(getBackground())
            .orElse(UIManager.getColor("Panel.background"));
        Color sc = Optional.ofNullable(target).orElse(ec);
        painter1 = new LinearGradientPaint(
            start, end, dist, new Color[] {sc.darker(), ec});
        painter2 = new LinearGradientPaint(
            start, end, dist, new Color[] {sc.brighter(), ec});
      }
      int h = getIconHeight() / 2;
      Graphics2D g2  = (Graphics2D) g.create();
      g2.setPaint(painter1);
      g2.fillRect(x, y, width, getIconHeight());
      g2.setPaint(painter2);
      g2.fillRect(x, y + h, width, getIconHeight() - h);
      g2.dispose();
    }

    @Override public int getIconWidth() {
      return 200; // sample width
    }

    @Override public int getIconHeight() {
      return height;
    }
  }
}
View in GitHub: Java, Kotlin

解説

TitledBorderと、上辺の余白のみグラデーション用のタイル・アイコンを描画するMatteBorderを組み合わせ、これを空のJLabelに設定することでTitledSeparatorを作成しています。

    • タイトルの垂直位置をデフォルトのTitledBorder.DEFAULT_POSITIONにしてSeparator上に重なるように表示
    • Java 1.6.0ではタイトルの上にSeparatorが表示される場合がある?(1.7.0では正常)
    • 垂直方向は未対応
    • タイトルの垂直位置が上(TitledBorder.ABOVE_TOP)でSeparatorの上に表示
    • デフォルトのJSeparatorを使用

参考リンク

コメント