José Leal
José Leal

Reputation: 8109

Rounded Swing JButton using Java

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...

Upvotes: 26

Views: 141994

Answers (9)

Capta1n_n9m0
Capta1n_n9m0

Reputation: 28

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);
        }
    }
}

Upvotes: 1

user1477929
user1477929

Reputation:

  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.

Upvotes: 1

Luka Kralj
Luka Kralj

Reputation: 456

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;
    }
}

Upvotes: 3

Reeba Babu
Reeba Babu

Reputation: 1

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

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

Upvotes: -1

Luffy
Luffy

Reputation: 1335

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);

Upvotes: 1

Lalchand
Lalchand

Reputation: 7827

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);
    }
}

Upvotes: 28

VonC
VonC

Reputation: 1325137

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.

Upvotes: 14

pek
pek

Reputation: 18035

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) {
    }
}

Upvotes: 1

Bombe
Bombe

Reputation: 83869

Opacity should be set to false, so

button.setOpaque(false);

could already be what you want.

Upvotes: 0

Related Questions