TITLE:OverlayLayoutで複数のJButtonを重ねて複合ボタンを作成
Posted by at 2012-11-26

OverlayLayoutで複数のJButtonを重ねて複合ボタンを作成

4つの扇形ボタンと円形ボタンを、`OverlayLayoutを設定したJPanel`に配置して、複合ボタンを作成します。
  • category: swing folder: CompoundButton title: OverlayLayoutで複数のJButtonを重ねて複合ボタンを作成 tags: [OverlayLayout, JButton, Icon] author: aterai pubdate: 2012-11-26T15:04:48+09:00 description: 4つの扇形ボタンと円形ボタンを、OverlayLayoutを設定したJPanelに配置して、複合ボタンを作成します。 image: https://lh6.googleusercontent.com/-0bLp9wWHHOw/ULIxE5DUtzI/AAAAAAAABX4/pRUF7k-l4D0/s800/CompoundButton.png hreflang:
       href: https://java-swing-tips.blogspot.com/2012/12/combine-five-jbuttons-to-make.html
       lang: en

概要

4つの扇形ボタンと円形ボタンを、OverlayLayoutを設定したJPanelに配置して、複合ボタンを作成します。
CompoundButton.png

サンプルコード

サンプルコード

private static JComponent makeCompoundButton(final Dimension d) {
  JPanel p = new JPanel() {
    @Override public Dimension getPreferredSize() {
      return d;
    }
  };
  p.setLayout(new OverlayLayout(p));
  p.add(new CompoundButton(d, ButtonLocation.NOTH));
  p.add(new CompoundButton(d, ButtonLocation.NORTH));
  p.add(new CompoundButton(d, ButtonLocation.SOUTH));
  p.add(new CompoundButton(d, ButtonLocation.EAST));
  p.add(new CompoundButton(d, ButtonLocation.WEST));
  p.add(new CompoundButton(d, ButtonLocation.CENTER));
  return p;
}

class CompoundButton extends JButton {
  protected final Color fc = new Color(100,150,255,200);
  protected final Color ac = new Color(230,230,230);
  protected final Color fc = new Color(100, 150, 255, 200);
  protected final Color ac = new Color(230, 230, 230);
  protected final Color rc = Color.ORANGE;
  protected Shape shape;
  protected Shape base = null;
  private final ButtonLocation bl;
  private final Dimension dim;
  public CompoundButton(Dimension d, ButtonLocation bl) {
    super();
    this.dim = d;
    this.bl = bl;
    setIcon(new Icon() {
      @Override public void paintIcon(Component c, Graphics g, int x, int y) {
        Graphics2D g2 = (Graphics2D)g.create();
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                  RenderingHints.VALUE_ANTIALIAS_ON);
        if(getModel().isArmed()) {
                            RenderingHints.VALUE_ANTIALIAS_ON);
        if (getModel().isArmed()) {
          g2.setColor(ac);
          g2.fill(shape);
        }else if(isRolloverEnabled() && getModel().isRollover()) {
        } else if (isRolloverEnabled() && getModel().isRollover()) {
          paintFocusAndRollover(g2, rc);
        }else if(hasFocus()) {
        } else if (hasFocus()) {
          paintFocusAndRollover(g2, fc);
        }else{
        } else {
          g2.setColor(getBackground());
          g2.fill(shape);
        }
        g2.dispose();
      }
#spanadd

#spanend
      @Override public int getIconWidth()  {
        return dim.width;
      }
#spanadd

#spanend
      @Override public int getIconHeight() {
        return dim.height;
      }
    });
    setFocusPainted(false);
    setContentAreaFilled(false);
    setBackground(new Color(250, 250, 250));
    initShape();
  }
#spanadd

#spanend
  @Override public Dimension getPreferredSize() {
    return dim;
  }
#spanadd

#spanend
  protected void initShape() {
    if(!getBounds().equals(base)) {
    if (!getBounds().equals(base)) {
      base = getBounds();
      float ww = getWidth() * 0.5f;
      float xx = ww * 0.5f;
      float ww = getWidth() * .5f;
      float xx = ww * .5f;
      Shape inner = new Ellipse2D.Float(xx, xx, ww, ww);
      if(ButtonLocation.CENTER==bl) {
      if (ButtonLocation.CENTER == bl) {
        shape = inner;
      }else{
      } else {
        Shape outer = new Arc2D.Float(
          1, 1, getWidth()-2, getHeight()-2,
          1, 1, getWidth() - 2, getHeight() - 2,
          bl.getStartDegree(), 90f, Arc2D.PIE);
        Area area = new Area(outer);
        area.subtract(new Area(inner));
        shape = area;
      }
    }
  }
#spanadd

#spanend
  private void paintFocusAndRollover(Graphics2D g2, Color color) {
    g2.setPaint(new GradientPaint(0, 0, color,
                    getWidth()-1, getHeight()-1, color.brighter(), true));
    g2.setPaint(new GradientPaint(
        0, 0, color, getWidth() - 1, getHeight() - 1, color.brighter(), true));
    g2.fill(shape);
    g2.setColor(getBackground());
  }
#spanadd

#spanend
  @Override protected void paintComponent(Graphics g) {
    initShape();
    super.paintComponent(g);
  }
#spanadd

#spanend
  @Override protected void paintBorder(Graphics g) {
    Graphics2D g2 = (Graphics2D)g;
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
              RenderingHints.VALUE_ANTIALIAS_ON);
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(getForeground());
    g2.draw(shape);
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
              RenderingHints.VALUE_ANTIALIAS_OFF);
    g2.dispose();
  }
#spanadd

#spanend
  @Override public boolean contains(int x, int y) {
    //initShape();
    // initShape();
    return shape.contains(x, y);
  }
}
View in GitHub: Java, Kotlin

解説

解説

  • 円形ボタン
    • JButtonの形を変更を使って、幅高さの半分の直径をもつ円ボタンを作成
    • `JButton#contains(...)`をオーバーライドして、図形内のみマウスカーソルが反応するように変更
    • JButtonの形を変更を使って幅高さの半分の直径をもつ円ボタンを作成
    • JButton#contains(...)をオーバーライドして図形内のみマウスカーソルが反応するように変更
  • 扇形ボタン
    • 東西南北に4つ配置するので、角の大きさは90度、始角はそれぞれ、45、135、225、-45度で`Arc2D`を作成
    • これらの`Arc2Dから上記の円形ボタンの領域を取り去って扇形に変形(Area#subtract(Area)`を使用)
    • 東西南北に4つ配置するので内角は90度、始角はそれぞれ45135225-45度でArc2Dを作成
    • これらのArc2DからArea#subtract(Area)メソッドを使用して上記の円形ボタンの領域を除去し扇形に変形
    • `JButton#contains(...)`をオーバーライドして、図形内のみマウスカーソルが反応するように変更
    • JButton#contains(...)をオーバーライドして図形内のみマウスカーソルが反応するように変更
  • 複合ボタン
    • 5つのボタンを、`OverlayLayoutを設定したJPanel`に配置
    • `JPanel#getPreferredSize()`をオーバーライドして、サイズが5つのボタンと同じになるように設定
    • 5つのボタンをOverlayLayoutを設定したJPanelに配置
    • JPanel#getPreferredSize()をオーバーライドしてサイズが5つのボタンですべて同じになるよう設定
    • これらの5つのボタンはクリック可能な領域が重なることはないので、JComponent#isOptimizedDrawingEnabled()メソッドをオーバーライドする必要はない

参考リンク

参考リンク

コメント

コメント