概要

任意のShapeとその形に透過色を設定した画像を使ってJButtonを作成します。

サンプルコード

class RoundButton extends JButton {
  protected Shape base;
  protected Shape shape

  public RoundButton() {
    this(null, null);
  }

  public RoundButton(Icon icon) {
    this(null, icon);
  }

  public RoundButton(String text) {
    this(text, null);
  }

  public RoundButton(Action a) {
    this();
    setAction(a);
  }

  public RoundButton(String text, Icon icon) {
    setModel(new DefaultButtonModel());
    init(text, icon);
    if (icon == null) {
      return;
    }
    setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
    setBackground(Color.BLACK);
    setContentAreaFilled(false);
    setFocusPainted(false);
    // setVerticalAlignment(SwingConstants.TOP);
    setAlignmentY(Component.TOP_ALIGNMENT);
    initShape();
  }

  protected void initShape() {
    if (!getBounds().equals(base)) {
      Dimension s = getPreferredSize();
      base = getBounds();
      shape = new Ellipse2D.Float(0, 0, s.width - 1, s.height - 1);
    }
  }

  @Override public Dimension getPreferredSize() {
    Icon icon = getIcon();
    Insets i = getInsets();
    int iw = Math.max(icon.getIconWidth(), icon.getIconHeight());
    return new Dimension(iw + i.right + i.left, iw + i.top + i.bottom);
  }

  @Override protected void paintBorder(Graphics g) {
    initShape();
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(getBackground());
    // g2.setStroke(new BasicStroke(1f));
    g2.draw(shape);
    g2.dispose();
  }

  @Override public boolean contains(int x, int y) {
    initShape();
    return shape.contains(x, y);
    // 以下、透過色が0でクリック不可にする場合の例
    // or return super.contains(x, y) && ((image.getRGB(x, y) >> 24) & 0xff) > 0;
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、JButtonに円形の画像を貼り付けてボタンを作成しています。

  • 円形で同サイズのPNG画像(円の外側が透過色)を3種類用意し以下のメソッドでJButtonに設定
    • setIcon
    • setPressedIcon
    • setRolloverIcon
  • setContentAreaFilled(false)などを設定してボタン自体の描画はしない
  • JButtonの推奨、最小、最大サイズを画像のサイズに合わせる
    • ただし、縁の線を描画するため、画像サイズより上下左右1px大きくなるようEmptyBorderを設定
  • containsをオーバーライドして円の外側をクリックしてもボタンが反応しないようにする
    • このサンプルでは、画像の透過色から円を生成している訳ではなく画像のサイズから円図形を別途作成
    • 画像の透過色からクリック可能な領域を設定する場合はJComponentの形状定義を変更するを参照
  • paintBorderをオーバーライドして元の縁は描画せずにその幅の線で独自に円を描画する
    • containsで使用した図形を利用

  • ボタンの揃えを変更するためにJPanelではなくBoxを利用しているのでJDK 5でもJDK 6と同じように描画するためにBox#paintComponentを以下のようにオーバーライド JDK 6で修正済み

参考リンク

コメント