I want to create a custom border with rounded corners.
Code -
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.border.AbstractBorder;
class JRoundedCornerBorder extends AbstractBorder
{
private static final long serialVersionUID = 7644739936531926341L;
private static final int THICKNESS = 5;
JRoundedCornerBorder()
{
super();
}
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
{
Graphics2D g2 = (Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if(c.hasFocus())
{
g2.setColor(Color.BLUE);
}
else
{
g2.setColor(Color.BLACK);
}
g2.setStroke(new BasicStroke(THICKNESS, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2.drawRect(x, y, width - 1, height - 1);
g2.dispose();
}
@Override
public Insets getBorderInsets(Component c)
{
return new Insets(THICKNESS, THICKNESS, THICKNESS, THICKNESS);
}
@Override
public Insets getBorderInsets(Component c, Insets insets)
{
insets.left = insets.top = insets.right = insets.bottom = THICKNESS;
return insets;
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
// Add button with custom border
final JButton button = new JButton("Hello");
button.setBorder(new JRoundedCornerBorder());
frame.add(button);
// Add button without custom border
frame.add(new JButton("Goodbye"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Result -
As you can see, Graphics.drawRect
completely ignores the BasicStroke.CAP_ROUND
and BasicStroke.JOIN_ROUND
attributes. Why?
As explained at Learning Java 2D, Part 1:
The key word is "centered". I believe that it is always the case that when drawing with thick strokes, Java2D will center the thickness of the line along the hypothetical, infinitesimally-thin line between the centers of the pixels at the starting and ending coordinates. For example, when drawing a vertical blue line 7 pixels thick, Java2D paints 3 pixels on each side of the hypothetical line segment that is being drawn.
In your example, the thickness is 5 pixels. You need to offset the coordinates to draw the stroke completely within the graphics clip. By moving in 2 pixels (or
THICKNESS/2
), the rounded corners become visible:the problem is the offset: you'r effectively cutting-off the border in the middle so the corners appear to be not rounded. Taking it into account (here only for the offset, need to adjust width as well)
Edit
fixed sloppy pixel counting :-)