概要

ボタンテキストが左揃えの非矩形JToggleButtonFlowLayoutを使って任意の幅だけ重ねて配置します。

サンプルコード

private static AbstractButton makeButton(
    String title, Color color, final int overlap, boolean first) {
  final ToggleButtonBarCellIcon icon = new ToggleButtonBarCellIcon();
  AbstractButton b = new JToggleButton(title) {
    @Override public boolean contains(int x, int y) {
      if (Objects.nonNull(icon) && Objects.nonNull(icon.area)) {
        return icon.area.contains(x, y);
      } else {
        return super.contains(x, y);
      }
    }

    @Override public Dimension getPreferredSize() {
      return new Dimension(icon.getIconWidth(), icon.getIconHeight());
    }

    @Override protected void paintComponent(Graphics g) {
      icon.paintIcon(this, g, 0, 0);
      super.paintComponent(g);
    }
  };
  b.setIcon(new Icon() {
    @Override public void paintIcon(Component c, Graphics g, int x, int y) {
      g.setColor(Color.GRAY);
      g.drawOval(x, y, 12, 12);
    }

    @Override public int getIconWidth() {
      return 12;
    }

    @Override public int getIconHeight() {
      return 12;
    }
  });
  b.setContentAreaFilled(false);
  int th = ToggleButtonBarCellIcon.TH;
  if (first) {
    b.setBorder(BorderFactory.createEmptyBorder(
        0, LINE_WIDTH + BI_GAP, 0, th));
  } else {
    b.setBorder(BorderFactory.createEmptyBorder(
        0, th + LINE_WIDTH + BI_GAP, 0, th));
  }
  b.setHorizontalAlignment(SwingConstants.LEFT);
  b.setFocusPainted(false);
  b.setOpaque(false);
  b.setBackground(color);
  return b;
}

private static JPanel makePanel(int overlap) {
  JPanel p = new JPanel(new FlowLayout(FlowLayout.LEADING, -overlap, 0)) {
    @Override public boolean isOptimizedDrawingEnabled() {
      return false;
    }
  };
  p.setBorder(BorderFactory.createEmptyBorder(0, overlap, 0, 0));
  p.setOpaque(false);
  return p;
}

private static JComponent makeBreadcrumbList(
    int overlap, Color color, List<String> list) {
  JPanel p = makePanel(overlap + LINE_WIDTH);
  ButtonGroup bg = new ButtonGroup();
  boolean f = true;
  for (String title : list) {
    AbstractButton b = makeButton(title, color, overlap, f);
    p.add(b);
    bg.add(b);
    f = false;
  }
  return p;
}
View in GitHub: Java, Kotlin

解説

FlowLayoutでボタンを重ねてパンくずリストを作成すると同様にFlowLayoutの配置間隔をマイナスにすることでボタンの重なりを実現していますが、こちらのサンプルではボタンテキストを左揃えにするためにJRadioButton#setIcon(Icon)JRadioButton#setHorizontalTextPosition(SwingConstants.CENTER)は使用せず、以下の3つのメソッドをオーバーライドしたJToggleButtonを使用しています。

  • JToggleButton#paintComponent(...)をオーバーライドして非矩形アイコンを描画
  • JToggleButton#getPreferredSize(...)をオーバーライドして推奨サイズがアイコンと同じになるように設定
  • JToggleButton#contains(...)をオーバーライドして非矩形アイコンの外側がマウスに反応しないように設定

  • アイコンの三角形部分に左揃えした文字列や長い文字列などが被らないようにするため、JToggleButtonにはEmptyBorderで開始辺と終了辺に余白を設定している
  • 最初のJToggleButtonの開始辺には三角形の高さ分の余白は必要ない

参考リンク

コメント