Mathew Jacob Mathew Jacob - 2 months ago 18
Java Question

Creating a Button with a round background color Java

I have the following button:

JButton S1L1Reset = new JButton("Reset");
S1L1Reset.setFont(new Font("Work Sans", Font.PLAIN, 14));
S1L1Reset.setForeground(new Color(90, 90, 90));
S1L1Reset.setBackground(new Color(220, 208, 192));
S1L1Reset.setOpaque(true);


I would like for the button to be round instead of boxed. I found another post that created a class that can make the border of the button round which is shown below.

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


When I make the changes to the button, to utilize this class, I get the following code:

JButton S1L1Reset = new JButton("Reset");
S1L1Reset.setFont(new Font("Work Sans", Font.PLAIN, 14));
S1L1Reset.setForeground(new Color(90, 90, 90));
S1L1Reset.setBackground(new Color(220, 208, 192));
S1L1Reset.setOpaque(true);
S1L1Reset.setBorderPainted(false);
S1L1Reset.setBorder(new RoundedBorder(20)); //new line of code added


The code however creates a button that looks like the following: Button. Is there any way that I can format the button such that the background color also remains within the round border.

Answer Source

The swing component uses UI delegate to draw itself, the background painting is done in the base class ComponentUI like this:

public void update(Graphics g, JComponent c) {
    if (c.isOpaque()) {
        g.setColor(c.getBackground());
        g.fillRect(0, 0, c.getWidth(),c.getHeight());
    }
    paint(g, c);
}

As you can see it uses fillRect so it must fill the background rectangularly. To change it, create a subclass of BasicButtonUI (whose subclasses are UI delegate of various look & feels) and override this method by filling round rect instead:

    S1L1Reset.setUI(new BasicButtonUI() {
        @Override
        public void update(Graphics g, JComponent c) {
            if (c.isOpaque()) {
                g.setColor(c.getBackground());
                g.fillRoundRect(0, 0, c.getWidth(),c.getHeight(), 20, 20);
            }
            paint(g, c);
        }
    });

But you'll need to handle various states of the button like mouse pressed background because these are done in the BasicButtonUI subclasses, since you no longer using these subclasses, you'll have to implement all that by yourself, like fill different colors based on current state of the button model (e.g. pressed, rollover). You may reference MetalButtonUI for example.

And maybe the call to setBorderPainted(false) is not needed? If you really want to utilize the round border you should need it to be painted.