23

Well, I have an image that I would like to put as a background to a button (or something clicable). The problem is that this image is round, so I need to show this image, without any borders, etc.

The JComponent that holds this button has a custom background, so the button really needs to only show the image.

After searching Google, I couldn't manage to do so. I have tried all the following, but with no luck:

button.setBorderPainted(false);
button.setContentAreaFilled(false);
button.setOpaque(true);

And after I paint the icon at the background, the button paints it, but holds an ugly gray background with borders, etc. I have also tried to use a JLabel and a JButton. And to paint an ImageIcon at it, but if the user resizes or minimizes the window, the icons disappear!

How can I fix this?

I just need to paint and round an image to a JComponent and listen for clicks at it...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
José Leal
  • 7,989
  • 9
  • 35
  • 54
  • You can check the previously answer thread of similar question : http://stackoverflow.com/questions/5120116/how-to-create-rounded-jbutton-in-java/31699716#31699716 – Tell Me How Jul 29 '15 at 11:57

9 Answers9

25

Create a new Jbutton:

    JButton addBtn = new JButton("+");
    addBtn.setBounds(x_pos, y_pos, 30, 25);
    addBtn.setBorder(new RoundedBorder(10)); //10 is the radius
    addBtn.setForeground(Color.BLUE);

while setting the border for a JButton, call the overridden javax.swing.border.Border class.

addBtn.setBorder(new RoundedBorder(10));

Here is the class

private static class RoundedBorder implements Border {

    private int radius;


    RoundedBorder(int radius) {
        this.radius = radius;
    }


    public Insets getBorderInsets(Component c) {
        return new Insets(this.radius+1, this.radius+1, this.radius+2, this.radius);
    }


    public boolean isBorderOpaque() {
        return true;
    }


    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        g.drawRoundRect(x, y, width-1, height-1, radius, radius);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lalchand
  • 7,627
  • 26
  • 67
  • 79
14

Did you try the following?

button.setOpaque(false);
button.setFocusPainted(false);
button.setBorderPainted(false);
button.setContentAreaFilled(false);
setBorder(BorderFactory.createEmptyBorder(0,0,0,0)); // Especially important

setBorder(null) might work, but there is a bug described at Sun explaining it is by design that the UI sets a border on a component unless the client sets a non-null border which does not implement the UIResource interface.

Rather than the JDK itself setting the border to an EmptyBorder when null is passed in, the clients should set an EmptyBorder themselves (a very easy workaround). That way there is no confusion about who's doing what in the code.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • You can check the previously answer thread of similar question : http://stackoverflow.com/questions/5120116/how-to-create-rounded-jbutton-in-java/31699716#31699716 – Tell Me How Jul 29 '15 at 11:56
3

I wrote an OvalButton class that can handle oval, circular and capsule-like shaped JButtons.

In your case, extend the OvalButton class and override getBackgroundImage() method to return the image you want to set as the background. Then add listeners and text as usually. Only a click on the oval/circular area triggers the action.

Example of your button class:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class ImageButton extends OvalButton {

    private BufferedImage image;

    public ImageButton() {
        super(); // Default is oval/circle shape.

        setBorderThickness(0); // Oval buttons have some border by default.

        try {
            image = ImageIO.read(new File("your_image.jpg")); // Replace with the path to your image.
        } 
        catch (IOException e) {
            e.printStackTrace();
            image = null;
        }
    }

    @Override
    protected BufferedImage getBackgroundImage() {
        return image;
    }
}
Luka Kralj
  • 446
  • 3
  • 12
1
  1. Drag a normal button to your panel

  2. Right click your button and go to properties:

border              = no border
border painted      = false
contentAreaFilled   = false
focusPainted        = false
opaque              = false
  1. Set an (icon) and a (rolloverIcon) by importing to project.
Community
  • 1
  • 1
1

You can try the following. It works fine for me, and I also faced the same issue with the button.

// Jbutton
JButton imageButton = new JButton();

// Buffered Icon
BufferedImage buttonIcon = null;

try {
    // Get the image and set it to the imageicon
    buttonIcon = ImageIO.read(getClass().getClassLoader().getResource("images/login.png"));
}
catch(Exception ex) {

}

// Set the image icon here
imageButton = new JButton(new ImageIcon(buttonIcon));
imageButton.setBorderPainted(false);
imageButton.setContentAreaFilled(false);
imageButton.setFocusPainted(false);
imageButton.setOpaque(false);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Luffy
  • 1,317
  • 1
  • 19
  • 41
1

I would recommend overriding paint(Graphics g) method as so:

class JImageButton extends JComponent implements MouseListener {
    private BufferedImage img = null;

    public JImageButton(BufferedImage img) {
        this.img = img;
        setMinimumSize(new Dimension(img.getWidth(), img.getHeight()));
        setOpaque(false);
        addMouseListener(this);
    }

    public void paintComponent(Graphics g) {
        g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null);
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }
}
pek
  • 17,847
  • 28
  • 86
  • 99
0

Opacity should be set to false, so

button.setOpaque(false);

could already be what you want.

Bombe
  • 81,643
  • 20
  • 123
  • 127
0

I just had the same problem and answer of @Lalchand inspired me. I created custom class for rounded borders, that is actually a modified version of LineBorder class. It draws two rectangles: inner and outer. For my case it is ok if border is colored like a background, but if you need something else, you should tinker with detentions of inner and outer. And as creative liberty I used subpixel rendering for smoother borders.

import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D;

class RoundedBorder extends LineBorder {

    private int radius;
    RoundedBorder(Color c, int thickness, int radius) {
        super(c, thickness, true);
        this.radius = radius;
    }
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        // adapted code of LineBorder class
        if ((this.thickness > 0) && (g instanceof Graphics2D)) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            Color oldColor = g2d.getColor();
            g2d.setColor(this.lineColor);

            Shape outer;
            Shape inner;

            int offs = this.thickness;
            int size = offs + offs;
            outer = new RoundRectangle2D.Float(x, y, width, height, 0, 0);
            inner = new RoundRectangle2D.Float(x + offs, y + offs, width - size, height - size, radius, radius);
            Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
            path.append(outer, false);
            path.append(inner, false);
            g2d.fill(path);
            g2d.setColor(oldColor);
        }
    }
}
-1

You can create an empty border to the button like this:

button.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));