Swing/RoundImageButton のバックアップの現在との差分(No.5)
TITLE:ImageIconの形でJButtonを作成
ImageIconの形でJButtonを作成
Posted by terai at 2008-07-21-
category: swing
folder: RoundImageButton
title: ImageIconの形でJButtonを作成
tags: [JButton, Shape, ImageIcon]
author: aterai
pubdate: 2008-07-21T16:27:56+09:00
description: 任意のShapeとその形に透過色を設定した画像を使ってJButtonを作成します。
image:
hreflang:
href: https://java-swing-tips.blogspot.com/2008/07/create-round-image-jbutton.html lang: en
概要
任意のShape
とその形に透過色を設定した画像を使ってJButton
を作成します。
Screenshot
Advertisement
概要
任意のShapeとその形に透過色を設定した画像を使ってJButtonを作成します。- &jnlp;
- &jar;
- &zip;
#screenshot
サンプルコード
#spanend
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
class RoundButton extends JButton {
protected Shape base;
protected Shape shape
#spanadd
#spanend
public RoundButton() {
this(null, null);
}
#spanadd
#spanend
public RoundButton(Icon icon) {
this(null, icon);
}
#spanadd
#spanend
public RoundButton(String text) {
this(text, null);
}
#spanadd
#spanend
public RoundButton(Action a) {
this();
setAction(a);
}
#spanadd
#spanend
public RoundButton(String text, Icon icon) {
setModel(new DefaultButtonModel());
init(text, icon);
if(icon==null) {
if (icon == null) {
return;
}
int iw = Math.max(icon.getIconWidth(), icon.getIconHeight());
int sw = 1;
setBorder(BorderFactory.createEmptyBorder(sw,sw,sw,sw));
Dimension dim = new Dimension(iw+sw+sw, iw+sw+sw);
setPreferredSize(dim);
setMaximumSize(dim);
setMinimumSize(dim);
setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
setBackground(Color.BLACK);
setContentAreaFilled(false);
setFocusPainted(false);
//setVerticalAlignment(SwingConstants.TOP);
// setVerticalAlignment(SwingConstants.TOP);
setAlignmentY(Component.TOP_ALIGNMENT);
initShape();
}
protected Shape shape, base;
#spanadd
#spanend
protected void initShape() {
if(!getBounds().equals(base)) {
if (!getBounds().equals(base)) {
Dimension s = getPreferredSize();
base = getBounds();
shape = new Ellipse2D.Float(0, 0, s.width-1, s.height-1);
shape = new Ellipse2D.Float(0, 0, s.width - 1, s.height - 1);
}
}
@Override
protected void paintBorder(Graphics g) {
#spanadd
#spanend
@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);
}
#spanadd
#spanend
@Override protected void paintBorder(Graphics g) {
initShape();
Graphics2D g2 = (Graphics2D)g;
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(getBackground());
//g2.setStroke(new BasicStroke(1.0f));
// g2.setStroke(new BasicStroke(1f));
g2.draw(shape);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
g2.dispose();
}
@Override
public boolean contains(int x, int y) {
#spanadd
#spanend
@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;
}
}
解説
上記のサンプルでは、JButtonに円形の画像を貼り付けてボタンを作成しています。- 円形、同サイズのPNG画像(円の外側が透過色)を三種類用意してJButtonに設定
- setIcon
- setPressedIcon
- setRolloverIcon
- setContentAreaFilled(false)などを設定して、ボタン自体の描画はしない
- 推奨、最小、最大サイズを画像のサイズに合わせる
- ただし、縁の線を描画するため、画像サイズより上下左右1pt大きくなるようEmptyBorderを設定している
- containsをオーバーライドして、円の外側をクリックしてもボタンが反応しないようにする
- 画像の透過色から、円を生成している訳ではなく、画像のサイズから円図形を別途作成している
- paintBorderをオーバーライドして、元の縁は描画せずにその幅の線で独自に円を描画する
- containsで使用した図形を利用
解説
上記のサンプルでは、JButton
に円形の画像を貼り付けてボタンを作成しています。
- - ボタンの揃えを変更するために、JPanelではなく、Boxを利用しているので、JDK 5 でも JDK 6 と同じように描画するために、Box#paintComponent を以下のようにオーバーライドしています。
- Bug ID: 4907674 Box disregards setBackground() even when set Opaque(true)
- 円形で同サイズの
PNG
画像(円の外側が透過色)を3
種類用意し以下のメソッドでJButton
に設定-
setIcon
-
setPressedIcon
-
setRolloverIcon
-
-
setContentAreaFilled(false)
などを設定してボタン自体の描画はしない -
JButton
の推奨、最小、最大サイズを画像のサイズに合わせる- ただし、縁の線を描画するため、画像サイズより上下左右
1px
大きくなるようEmptyBorder
を設定
- ただし、縁の線を描画するため、画像サイズより上下左右
-
contains
をオーバーライドして円の外側をクリックしてもボタンが反応しないようにする- このサンプルでは、画像の透過色から円を生成している訳ではなく画像のサイズから円図形を別途作成
- 画像の透過色からクリック可能な領域を設定する場合はJComponentの形状定義を変更するを参照
-
paintBorder
をオーバーライドして元の縁は描画せずにその幅の線で独自に円を描画する-
contains
で使用した図形を利用
-
#screenshot(,screenshot1.png)
- -
-
ボタンの揃えを変更するためにJPanel
ではなくBox
を利用しているのでJDK 5
でもJDK 6
と同じように描画するためにBox#paintComponent
を以下のようにオーバーライドJDK 6
で修正済み- JDK-4907674 Box disregards setBackground() even when set Opaque(true) - Java Bug System
-
private final Box box = // JDK 6 Box.createHorizontalBox(); // JDK 5 new Box(BoxLayout.X_AXIS) { protected void paintComponent(Graphics g) { if(ui != null) { @Override protected void paintComponent(Graphics g) { if (ui != null) { super.paintComponent(g); }else if(isOpaque()) { } else if (isOpaque()) { g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); } } };
- -
以下のようなButtonUIを使って、JButtonをオーバーライドしない方法もあります。
#spanend #spandel JButton button = new JButton(icon); #spanend #spandel button.setUI(new RoundImageButtonUI()); #spanend #spandel
#spanend #spandel class RoundImageButtonUI extends BasicButtonUI{ #spanend protected Shape shape, base; @Override protected void installDefaults(AbstractButton b) { super.installDefaults(b); Icon icon = b.getIcon(); if(icon==null) return; int iw = Math.max(icon.getIconWidth(), icon.getIconHeight()); int sw = 1; b.setBorder(BorderFactory.createEmptyBorder(sw,sw,sw,sw)); b.setContentAreaFilled(false); b.setFocusPainted(false); b.setOpaque(false); b.setBackground(Color.BLACK); Dimension dim = new Dimension(iw+sw+sw, iw+sw+sw); b.setPreferredSize(dim); b.setMaximumSize(dim); b.setMinimumSize(dim); //b.setVerticalAlignment(SwingConstants.TOP); b.setAlignmentY(Component.TOP_ALIGNMENT); initShape(b); } @Override protected void installListeners(AbstractButton b) { BasicButtonListener listener = new BasicButtonListener(b) { @Override public void mousePressed(MouseEvent e) { AbstractButton b = (AbstractButton) e.getSource(); initShape(b); if(shape.contains(e.getX(), e.getY())) { super.mousePressed(e); } } @Override public void mouseEntered(MouseEvent e) { if(shape.contains(e.getX(), e.getY())) { super.mouseEntered(e); } } @Override public void mouseMoved(MouseEvent e) { if(shape.contains(e.getX(), e.getY())) { super.mouseEntered(e); }else{ super.mouseExited(e); } } }; if(listener != null) { b.addMouseListener(listener); b.addMouseMotionListener(listener); b.addFocusListener(listener); b.addPropertyChangeListener(listener); b.addChangeListener(listener); } } @Override public void paint(Graphics g, JComponent c) { super.paint(g, c); Graphics2D g2 = (Graphics2D)g; initShape(c); //Border g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setColor(c.getBackground()); //g2.setStroke(new BasicStroke(1.0f)); g2.draw(shape); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); } private void initShape(JComponent c) { if(!c.getBounds().equals(base)) { Dimension s = c.getPreferredSize(); base = c.getBounds(); shape = new Ellipse2D.Float(0, 0, s.width-1, s.height-1); } } #spandel } #spanend #spandel
参考リンク
- アクア風の球体の描き方(GIMPチュートリアル) > ロゴ・ボタン | GIMP思い込みチュートリアル(GIMPの使い方)
- Bug ID: 4907674 Box disregards setBackground() even when set Opaque(true)