Rounded Border JPanel (JPanel graphics improvements) – CodeProject

 

Rounded Border JPanel (JPanel graphics improvements)

By b4rc0ll0 | 10 Oct 2010

JavaWindowsLinuxDesignIntermediateSwing

Reusable extension of JPanel with rounded borders, shadow and antialiasing

Sponsored Links

Introduction

Swing Framework extensibility allows us to create very advanced graphics component for a better view of our Jframes more than directly Look&Feel management, and more simply.

Basically a JComponent is a void Bounded Box that can be added into swing containers.

It can be extended by a simple plain class, and overriding paintComponent method, we can draw everything we need in a Bounded Box. In this way we can re-create all basic swing components like Buttons, Labels, Panels... with relative events.

Using the Code

In this case, we will review a JPanel extension (instead of JComponent extension) because we want to create a Container component (like JPanel!) but with some graphics improvements:

Collapse

public class RoundedPanel extends JPanel {

    /** Stroke size. it is recommended to set it to 1 for better view */
    protected int strokeSize = 1;
    /** Color of shadow */
    protected Color shadowColor = Color.black;
    /** Sets if it drops shadow */
    protected boolean shady = true;
    /** Sets if it has an High Quality view */
    protected boolean highQuality = true;
    /** Double values for Horizontal and Vertical radius of corner arcs */
    protected Dimension arcs = new Dimension(20, 20);
    /** Distance between shadow border and opaque panel border */
    protected int shadowGap = 5;
    /** The offset of shadow.  */
    protected int shadowOffset = 4;
    /** The transparency value of shadow. ( 0 - 255) */
    protected int shadowAlpha = 150;

	//FOLLOWING CODES GOES HERE
} 

We have created a simple class extending JPanel. It has some properties for the improvements (see inline comments for properties descriptions).

Attention!! If you want to use this class directly in a visual GUI editor, like integrated Netbeans Editor, we must write a void constructor, because Editor can't directly know constructor parameter of our components:

Collapse

 public RoundedPanel() {
        super();
        setOpaque(false);
    }

We call super() father constructor and setOpaque(false) to create a transparent void bounded box, where we can freely draw custom component.

Now we can override the paintComponent method:

Collapse

 @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int width = getWidth();
        int height = getHeight();
        int shadowGap = this.shadowGap;
        Color shadowColorA = new Color(shadowColor.getRed(), 
	shadowColor.getGreen(), shadowColor.getBlue(), shadowAlpha);
        Graphics2D graphics = (Graphics2D) g;

        //Sets antialiasing if HQ.
        if (highQuality) {
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
			RenderingHints.VALUE_ANTIALIAS_ON);
        }

        //Draws shadow borders if any.
        if (shady) {
            graphics.setColor(shadowColorA);
            graphics.fillRoundRect(
                    shadowOffset,// X position
                    shadowOffset,// Y position
                    width - strokeSize - shadowOffset, // width
                    height - strokeSize - shadowOffset, // height
                    arcs.width, arcs.height);// arc Dimension
        } else {
            shadowGap = 1;
        }

        //Draws the rounded opaque panel with borders.
        graphics.setColor(getBackground());
        graphics.fillRoundRect(0, 0, width - shadowGap, 
		height - shadowGap, arcs.width, arcs.height);
        graphics.setColor(getForeground());
        graphics.setStroke(new BasicStroke(strokeSize));
        graphics.drawRoundRect(0, 0, width - shadowGap, 
		height - shadowGap, arcs.width, arcs.height);

        //Sets strokes to default, is better.
        graphics.setStroke(new BasicStroke());
    }

The method has five macro sections. The header section calls super overridden method and declares main variables: (width, height) are the current size of our component; shadowGap is an override of homonymous property, we will see later why; shadowColor is the color property with transparency added; and graphics is the Graphics object passed by method parameters that represent the canvas where we can paint on (Graphics2D cast is more powerful, see antialiasing).

The next section checks if highQuality is true, so enable antialiasing on canvas for all shapes drawn after.

Alike shady determinates if component draws shadow. Shadow is a simple roundRect, usually black, with left-top and right-bottom corners parameterized by shadowOffset value.

Above a possible shadow, the component draws the opaque panel with a thin edge. Here the right-top and right bottom positions are parameterized by shadowGap.

Graphically the order 1) -> 2) -> 3) of layer must be this, due to overlap:

screenshot2.PNG

The footer section is used to reset parameters that we have distorted. In fact, if we will not reset strokes, the next component added to this panel will have a distorted border.

Conclusions

With these simple few lines, we have created a solid redestributable swing component that look like this:

 

We can see tree RoundedPanel here: violet, green and blue one, each with a different arcs dimension that determinates the curvature of corners. The best size is [10,10] like blue panel, because an excessive curve (like violet) can cut out upper-inner components (try set [80,80] .. ).

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0

About the Author