---
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
---
* Summary [#summary]
`4`つの扇形ボタンと円形ボタンを、`OverlayLayout`を設定した`JPanel`に配置して、複合ボタンを作成します。
#download(https://lh6.googleusercontent.com/-0bLp9wWHHOw/ULIxE5DUtzI/AAAAAAAABX4/pRUF7k-l4D0/s800/CompoundButton.png)
* Source Code Examples [#sourcecode]
#code(link){{
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.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 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();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (getModel().isArmed()) {
g2.setColor(ac);
g2.fill(shape);
} else if (isRolloverEnabled() && getModel().isRollover()) {
paintFocusAndRollover(g2, rc);
} else if (hasFocus()) {
paintFocusAndRollover(g2, fc);
} else {
g2.setColor(getBackground());
g2.fill(shape);
}
g2.dispose();
}
@Override public int getIconWidth() {
return dim.width;
}
@Override public int getIconHeight() {
return dim.height;
}
});
setFocusPainted(false);
setContentAreaFilled(false);
setBackground(new Color(250, 250, 250));
initShape();
}
@Override public Dimension getPreferredSize() {
return dim;
}
protected void initShape() {
if (!getBounds().equals(base)) {
base = getBounds();
float ww = getWidth() * .5f;
float xx = ww * .5f;
Shape inner = new Ellipse2D.Float(xx, xx, ww, ww);
if (ButtonLocation.CENTER == bl) {
shape = inner;
} else {
Shape outer = new Arc2D.Float(
1, 1, getWidth() - 2, getHeight() - 2,
bl.getStartDegree(), 90f, Arc2D.PIE);
Area area = new Area(outer);
area.subtract(new Area(inner));
shape = area;
}
}
}
private void paintFocusAndRollover(Graphics2D g2, Color color) {
g2.setPaint(new GradientPaint(
0, 0, color, getWidth() - 1, getHeight() - 1, color.brighter(), true));
g2.fill(shape);
g2.setColor(getBackground());
}
@Override protected void paintComponent(Graphics g) {
initShape();
super.paintComponent(g);
}
@Override protected void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getForeground());
g2.draw(shape);
g2.dispose();
}
@Override public boolean contains(int x, int y) {
// initShape();
return shape.contains(x, y);
}
}
}}
* Description [#explanation]
* Description [#description]
- 円形ボタン
-- [[JButtonの形を変更>Swing/RoundButton]]を使って幅高さの半分の直径をもつ円ボタンを作成
-- `JButton#contains(...)`をオーバーライドして図形内のみマウスカーソルが反応するように変更
- 扇形ボタン
-- 東西南北に`4`つ配置するので内角は`90`度、始角はそれぞれ`45`、`135`、`225`、`-45`度で`Arc2D`を作成
-- これらの`Arc2D`から`Area#subtract(Area)`メソッドを使用して上記の円形ボタンの領域を除去し扇形に変形
--- [[Mouseで画像を移動、回転>Swing/MouseDrivenImageRotation]]
-- `JButton#contains(...)`をオーバーライドして図形内のみマウスカーソルが反応するように変更
- 複合ボタン
-- `5`つのボタンを`OverlayLayout`を設定した`JPanel`に配置
-- `JPanel#getPreferredSize()`をオーバーライドしてサイズが`5`つのボタンですべて同じになるよう設定
--- [[OverlayLayoutの使用>Swing/OverlayLayout]]
-- これらの`5`つのボタンはクリック可能な領域が重なることはないので、[https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/JComponent.html#isOptimizedDrawingEnabled-- JComponent#isOptimizedDrawingEnabled()]メソッドをオーバーライドする必要はない
* Reference [#reference]
- [[OverlayLayoutの使用>Swing/OverlayLayout]]
- [[JButtonの形を変更>Swing/RoundButton]]
- [[Mouseで画像を移動、回転>Swing/MouseDrivenImageRotation]]
* Comment [#comment]
#comment
#comment