Add a neat rounded border that I found here to my JPanel. Very happy with the end result except for one small issue... on a mouse enter/mouse exit event I resize the border to highlight BUT the JLabel in the center of the JPanel moves to accommodate the extra space required for the rounded border.. I know this because I don't see this undesired behaviour when I use a standard line border!
Any tips/tricks/ideas welcome.. basically I want a rounded corner and the ability to change it's thickness but want to fix the JLabel's position at the center of the JPanel and ensure it doesn't move. Quick example below of undesired behaviour, simply mouse enter the JPanel to observe the JLabel move:
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
public class temp extends JPanel {
private Border brdrMouseEnter;
private Border brdrMouseExit;
public temp(){
brdrMouseExit = new RoundedBorder(Color.gray, 1, 12, 0);
brdrMouseEnter = new RoundedBorder(Color.blue, 4, 12, 0);
this.setLayout(new BorderLayout());
this.setBorder(brdrMouseExit);
this.add(new JLabel("test", JLabel.CENTER));
this.addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent e) {
JPanel thisPanel = (JPanel)e.getSource();
thisPanel.setBorder(brdrMouseEnter);
}
public void mouseExited(MouseEvent e) {
JPanel thisPanel = (JPanel)e.getSource();
thisPanel.setBorder(brdrMouseExit);
}
});
}
public class RoundedBorder extends AbstractBorder {
private Color color;
private int thickness = 4;
private int radii = 8;
private int pointerSize = 7;
private Insets insets = null;
private BasicStroke stroke = null;
private int strokePad;
private int pointerPad = 4;
private boolean left = true;
RenderingHints hints;
RoundedBorder(Color color){
new RoundedBorder(color, 4, 8, 7);
}
RoundedBorder(Color color, int thickness, int radii, int pointerSize) {
this.thickness = thickness;
this.radii = radii;
this.pointerSize = pointerSize;
this.color = color;
stroke = new BasicStroke(thickness);
strokePad = thickness / 2;
hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int pad = radii + strokePad;
int topPad = pad + pointerSize + strokePad;
insets = new Insets(topPad, pad, pad, pad);
}
RoundedBorder(Color color, int thickness, int radii, int pointerSize, boolean left) {
this(color, thickness, radii, pointerSize);
this.left = left;
}
@Override
public Insets getBorderInsets(Component c) {
return insets;
}
@Override
public Insets getBorderInsets(Component c, Insets insets) {
return getBorderInsets(c);
}
@Override
public void paintBorder(
Component c,
Graphics g,
int x, int y,
int width, int height) {
Graphics2D g2 = (Graphics2D) g;
int topLineY = height - thickness - pointerSize;
RoundRectangle2D.Double bubble = new RoundRectangle2D.Double(
0 + strokePad,
0 + pointerSize,
width - thickness,
topLineY,
radii,
radii);
Polygon pointer = new Polygon();
// if (left) {
// left point
pointer.addPoint(
width - 25/*(strokePad + radii + pointerPad)*/,
strokePad +pointerSize);
// right point
pointer.addPoint(
width - 15/*(strokePad + radii + pointerPad + pointerSize)*/,
strokePad +pointerSize);
// bottom point
pointer.addPoint(
width - (25-(10/2))/*(strokePad + radii + pointerPad + (pointerSize / 2)*/,
strokePad);
// }
Area area = new Area(bubble);
area.add(new Area(pointer));
g2.setRenderingHints(hints);
// Paint the BG color of the parent, everywhere outside the clip
// of the text bubble.
Component parent = c.getParent();
if (parent!=null) {
Color bg = parent.getBackground();
Rectangle rect = new Rectangle(0,0,width, height);
Area borderRegion = new Area(rect);
borderRegion.subtract(area);
g2.setClip(borderRegion);
g2.setColor(bg);
g2.fillRect(0, 0, width, height);
g2.setClip(null);
}
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(area);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
temp ex = new temp();
//ex.setVisible(true);
JFrame f = new JFrame();
f.getContentPane().add(ex);
f.setSize(640, 480);
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(1);
}
});
}
});
}
}