Search code examples
javaswingjpaneljbuttonnimbus

How to draw a JPanel as a Nimbus JButton?


In Nimbus look and feel JButtons have a very tidy and accurate look, with rounded border and nice background.
I'd like to render a JPanel with the very same look (obviously it won't have pressed state etc).
What are my options?


Solution

  • The easiest way to get "Button look" on a JPanel is probably by extending the JPanel and override paintComponent.

    Here is the Nimbus JButton look:

    enter image description here

    And here is my implementation of a similar look on a JPanel (I added an empty border around for showing this example, and the corners are not translucent):

    enter image description here

    Here is my code (using gradients):

    public class ColorDemo extends JPanel {
    
        private final int gradientSize = 18;
        private final Color lighterColor = new Color(250, 250, 250);
        private final Color darkerColor = new Color(225, 225, 230);
        private final Color edgeColor = new Color(140, 145, 145);
        private final Stroke edgeStroke = new BasicStroke(1);
        private final GradientPaint upperGradient = new GradientPaint(
                0, 0, lighterColor,
                0, gradientSize, darkerColor);
    
    
        @Override
        public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D)g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
                                RenderingHints.VALUE_ANTIALIAS_ON);
            GradientPaint lowerGradient = new GradientPaint(
                    0, getHeight()-gradientSize-1, darkerColor,
                    0, getHeight(), lighterColor);
            g2.setPaint(upperGradient);
            g2.fillRect(0, 0, getWidth()-1 , gradientSize);
            g2.setPaint(darkerColor);
            g2.fillRect(0, gradientSize, getWidth()-1, getHeight()-gradientSize-1);
            g2.setPaint(lowerGradient);
            g2.fillRect(0, getHeight()-gradientSize, getWidth()-1, getHeight()-1);
            g2.setStroke(edgeStroke);
            g2.setPaint(edgeColor);
            g2.drawRoundRect(0, 0, getWidth()-1, getHeight()-1,
                                   gradientSize/2, gradientSize/2);
        }
    }
    

    UPDATE

    Here is an improved paintComponent method by AgostinoX that solved the corner issue in my code.

        @Override
        public void paintComponent(Graphics g) {
    
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALI‌​AS_ON);
            float gradientPerc = (float)gradientSize/getHeight();
            LinearGradientPaint lgp = new LinearGradientPaint(0,0,0,getHeight()-1,
               new float[] {0, gradientPerc, 1-gradientPerc, 1f},
               new Color[] {lighterColor, darkerColor, darkerColor, lighterColor});
            g2.setPaint(lgp);
            g.fillRoundRect(0, 0, getWidth()-1, getHeight()-1,
                gradientSize, gradientSize);
            g2.setColor(edgeColor);
            g2.setStroke(edgeStroke);
            g.drawRoundRect(0, 0, getWidth()-1, getHeight()-1,
                gradientSize, gradientSize);
        }
    

    See also my answer to How to hide the arrow buttons in a JScrollBar on how you can customize the look and feel for Nimbus. And see the Nimbus defaults for colors and painters.