How to remove edges from JButton after border radius?

80 Views Asked by At

Finally it's done to make rounded corners for JButton, i'm tired to remove the edges that show after border radius without using transparent images

Screenshot of JButton

https://i.stack.imgur.com/8UxyX.jpg

here's the code

        JButton button = new JButton("SIGN IN");
        Color borderColor = Color.decode("#2c3338");
        button.setBorder(new RoundedBorder(20, borderColor));
        button.setFont(new Font("SansSerif", Font.BOLD, 11));
        button.setBackground(Color.decode("#ea4c88"));
        button.setForeground(Color.WHITE);
        button.setFocusPainted(false);
        button.setContentAreaFilled(false);
        button.setOpaque(true);
        button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        button.setBounds(135, 233, 280, 44);
        container.add(button);
public class RoundedBorder implements Border {

    private int radius;
    private Color borderColor;

    public RoundedBorder(int Radius, Color BorderColor) {
        radius = Radius;
        borderColor = BorderColor;
    }

    public Insets getBorderInsets(Component c) {
        return new Insets(radius, radius, radius, radius);
    }

    public boolean isBorderOpaque() {
        return true;
    }

    public void paintBorder(Component c, Graphics Graphics, int x, int y, int width, int height) {
        Graphics2D Graphics2D = (Graphics2D) Graphics.create();
        Graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Graphics2D.setColor(borderColor);
        Graphics2D.setStroke(new BasicStroke(2));
        Graphics2D.drawRoundRect(x, y, width - 1, height - 1, radius, radius);
        Graphics2D.dispose();
    }
    
}
1

There are 1 best solutions below

0
MadProgrammer On

Border isn't meant to "fill" and based on the order of the paint chain, it's called AFTER the background is painted.

A possible solution is to "fake" it instead, for example...

enter image description here

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setBorder(new EmptyBorder(32, 32, 32, 32));
            setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.ipadx = 40;
            add(new RoundedButton("Sign In"), gbc);
        }

    }

    public class RoundedButton extends JButton {

        private Color borderColor = Color.decode("#2c3338");
        private int radius = 20;

        public RoundedButton(String text) {
            super(text);
            //button.setBorder(new RoundedBorder(20, borderColor))/;
            setFont(new Font("SansSerif", Font.BOLD, 11));
            setBackground(Color.decode("#ea4c88"));
            setForeground(Color.WHITE);
            setFocusPainted(false);
            setContentAreaFilled(false);
            setBorderPainted(false);
            setOpaque(false);
            setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        }

        @Override
        public Insets getInsets() {
            return new Insets(radius, radius, radius, radius);
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(getBackground());
            g2d.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, radius, radius);
            g2d.setColor(borderColor);
            g2d.setStroke(new BasicStroke(2));
            g2d.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, radius, radius);
            g2d.dispose();
            super.paintComponent(g);
        }
    }
}

Please also note, the simple use of GridBagLayout in the example, which deals with calculating the size and position of the button, the addition of the iPadx constraint to increase the width of the button and obviously, the overridden getInsets method of the JButton.

Also not the order in which the button is painted, you MUST paint the background BEFORE calling super.paintComponent, as the super method will paint the text

Button corners don't get painted over by borders, they are moved outwards instead demonstrates an alternative which can be used to change ANY (or all) JButton, rather then needing to use a dedicate class. This example simple creates a new ButtonUI which can be applied to ANY instance of JButton to change the way in which it's painted, arguably making it a better solution where you already have a pre-existing UI.