Search code examples
javaswinggraphicsgradientpaintcomponent

What do I need to do to replicate this component with gradient paint?


I attempted to replicate this component (at the bottom of the post), but I can't seem to get it to look nice.

enter image description here

So I'm wondering, how do I replicate this gradient paint? Or if it isn't the gradient paint, what do I do to get similar results?

My attempt turned out very flat black compared to this component. Also it had the JFrame options (close, minimize, etc) and it didn't have a 'rounded' look to the components. I'm looking for someone who can improve what I have and explain where I went wrong. I know I can simply use an already made Look and Feel, but I would like to get my example project as close as possible to the BitDefender GUI in the image excluding the text. (I can provide code if need be)

Also notice I skipped the panel between Background and the 'Virus Shield', 'Auto Scan', 'My BitDefender' panels. I did this mainly because I wanted to keep my SSCCE as small as possible.

Also I want to note that setting the insets to gbc.insets = new Insets(2,10,2,10); on the 3 TopPanels makes it look much closer to the spacing of the BitDefender GUI. (I just didn't have the time to upload the picture at the moment. So I left the code as is, but I do realize that it can be updated to the above insets.

enter image description here

Edit - Updated with more source

Here is my code / SSCCE (it is 3 separate classes, but I consilidated them into one .java)

package testgui;

import java.awt.*;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class TestGui {

    public TestGui() {
        JFrame frame = new JFrame();
        MidPanel midPanel = new MidPanel();
        TopPanel topPanel1 = new TopPanel();
        TopPanel topPanel2 = new TopPanel();
        TopPanel topPanel3 = new TopPanel();
        JLabel appName = new JLabel("MyApplication");
        JLabel verNum = new JLabel("version 1.0");
        Font verFont = new Font("Tahoma", Font.BOLD, 11);
        Font nameFont = new Font("Tahoma", Font.BOLD, 14);

        GridBagConstraints gbc = new GridBagConstraints();

        appName.setForeground(Color.WHITE);
        appName.setFont(nameFont);
        verNum.setForeground(Color.WHITE);
        verNum.setFont(verFont);

        //add program name and version number
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 5);
        midPanel.add(appName, gbc);

        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 5);
        midPanel.add(verNum, gbc);

        //add 3 example top panels to midpanel
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.anchor = GridBagConstraints.NORTHWEST;
        gbc.insets = new Insets(1,2,1,2);
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        midPanel.add(topPanel1, gbc);

        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.insets = new Insets(1,2,1,2);
        gbc.anchor = GridBagConstraints.NORTHWEST;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        midPanel.add(topPanel2, gbc);

        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.anchor = GridBagConstraints.NORTHWEST;
        gbc.insets = new Insets(1,2,1,2);
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        midPanel.add(topPanel3, gbc);

        //add panel to push other panels to top
        gbc.gridx = 0;
        gbc.gridy = 5;
        gbc.fill = GridBagConstraints.VERTICAL;
        gbc.weighty = 1.0;
        JPanel invisPanel = new JPanel();
        invisPanel.setOpaque(false);
        midPanel.add(invisPanel, gbc);

        frame.getContentPane().add(midPanel);
        frame.pack();
        frame.setVisible(true);
    }

    //test it out
    public static void main(String[] args) {
        new TestGui();
    }

    //class for the top 3 panels
    private class TopPanel extends JPanel {

        private int maxLength;
        private boolean cyclic;


        public TopPanel() {
            initComponents();
            setOpaque(false);
            cyclic = true;
            maxLength = 0;
        }

        @Override
        public void paintComponent(Graphics g) {
            if(isOpaque()) {
                super.paintComponent(g);
                return;
            }

            int width = getWidth();
            int height = getHeight();

            GradientPaint paint = null;

            Color top = new Color(50, 50, 50);
            Color btm = new Color(19, 19, 19);

            paint = new GradientPaint(width / 2, 0, top, width / 2, maxLength > 0 ? maxLength : height, btm, cyclic);

            if(paint == null) {
                throw new RuntimeException("Invalid direction specified in GamerTagPanel");
            }

            Graphics2D g2d = (Graphics2D) g;
            Paint oldPaint = g2d.getPaint();
            g2d.setPaint(paint);
            g2d.fillRect(0, 0, width, height);
            g2d.setPaint(oldPaint);
            super.paintComponent(g);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 200);  
        }

        private void initComponents() {
            GridBagConstraints gbc;
            JLabel jLabel1 = new JLabel();
            JLabel jLabel2 = new JLabel();

            setBorder(BorderFactory.createLineBorder(new Color(204,204,204)));
            setLayout(new GridBagLayout());

            jLabel1.setFont(new Font("Tahoma", Font.BOLD, 11));
            jLabel1.setForeground(new Color(255, 255, 255));
            jLabel1.setText("Scanning...");
            gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.insets = new Insets(5, 5, 5, 5);
            add(jLabel1, gbc);

            jLabel2.setFont(new java.awt.Font("Tahoma", Font.BOLD, 11)); 
            jLabel2.setForeground(new java.awt.Color(255, 255, 255));
            jLabel2.setText("C:\\Directory\\Folder\\SubFolder\\SpecificFolder\\File.file");
            gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 1;
            gbc.gridwidth = 2;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.weightx = 1.0;
            gbc.insets = new Insets(5, 5, 5, 5);
            add(jLabel2, gbc);
        }
    }

    public class MidPanel extends JPanel {

        private int maxLength;
        private boolean cyclic;

        public MidPanel() {
            setLayout(new GridBagLayout());
            setOpaque(false);
            maxLength = 0;
            cyclic = false;
        }

        @Override
        public void paintComponent(Graphics g) {
            if(isOpaque()) {
                super.paintComponent(g);
                return;
            }

            int width = getWidth();
            int height = getHeight();

            GradientPaint paint = null;

            Color top = new Color(75, 75, 75);
            Color btm = new Color(19, 19, 19);

            paint = new GradientPaint(width / 2, 0, top, width / 2, maxLength > 0 ? maxLength : height, btm, cyclic);

            if(paint == null) {
                throw new RuntimeException("Invalid direction specified in GamerTagPanel");
            }

            Graphics2D g2d = (Graphics2D) g;
            Paint oldPaint = g2d.getPaint();
            g2d.setPaint(paint);
            g2d.fillRect(0, 0, width, height);
            g2d.setPaint(oldPaint);
            super.paintComponent(g);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 400);
        }
    }
}

Thanks JoopEggen for pointing out my issue with colors on the GradientPaint. It helped out quite a bit. I'm still looking for someone to put together a better/closer looking example. This is my first go at overriding the paintComponent in such a way.


Solution

  • Let's do some reverse engineering first. Several simplifications can be maid during that process. Moreover, I would say it is also possible to enhance that application look, because first impression is far from being very positive.

    enter image description here

    Basically the following elements can be found behind that design:

    • gradients
    • properly selected colors
    • rounded corners
    • outlines

    enter image description here

    Please note, rounded corners, outlines are important. BTW, some gradients can be optimized to provide clean and simple design. Please check The Battle Between Flat Design And Skeuomorphism for additional motivation.

    Your example was modified and looks like the following (it just a visual result):

    enter image description here

    I've used the following colors:

    enter image description here

    Code:

    public class TestGui {
    
        public TestGui() {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            MidPanel midPanel = new MidPanel();
            TopPanel topPanel1 = new TopPanel();
            TopPanel topPanel2 = new TopPanel();
            TopPanel topPanel3 = new TopPanel();
    
            JLabel appName = new JLabel("MyApplication");
            JLabel verNum = new JLabel("version 1.0");
            Font verFont = new Font("Tahoma", Font.BOLD, 11);
            Font nameFont = new Font("Tahoma", Font.BOLD, 14);
    
            GridBagConstraints gbc = new GridBagConstraints();
    
            appName.setForeground(Color.WHITE);
            appName.setFont(nameFont);
            verNum.setForeground(new Color(0xFF9f9f9f));
            verNum.setFont(verFont);
    
            //add program name and version number
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.WEST;
            gbc.insets = new Insets(5, 5, 5, 5);
            midPanel.add(appName, gbc);
    
            gbc.gridx = 0;
            gbc.gridy = 1;
            gbc.anchor = GridBagConstraints.WEST;
            gbc.insets = new Insets(5, 5, 5, 5);
            midPanel.add(verNum, gbc);
    
            //add 3 example top panels to midpanel
            gbc.gridx = 0;
            gbc.gridy = 2;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.insets = new Insets(1,2,1,2);
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 1.0;
            midPanel.add(topPanel1, gbc);
    
            gbc.gridx = 0;
            gbc.gridy = 3;
            gbc.insets = new Insets(1,2,1,2);
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 1.0;
            midPanel.add(topPanel2, gbc);
    
            gbc.gridx = 0;
            gbc.gridy = 4;
            gbc.anchor = GridBagConstraints.NORTHWEST;
            gbc.insets = new Insets(1,2,1,2);
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 1.0;
            midPanel.add(topPanel3, gbc);
    
            //add panel to push other panels to top
            gbc.gridx = 0;
            gbc.gridy = 5;
            gbc.fill = GridBagConstraints.VERTICAL;
            gbc.weighty = 1.0;
            JPanel invisPanel = new JPanel();
            invisPanel.setOpaque(false);
            midPanel.add(invisPanel, gbc);
    
            frame.getContentPane().add(midPanel);
            frame.pack();
            frame.setVisible(true);
        }
    
        //test it out
        public static void main(String[] args) {
            new TestGui();
        }
    
        //class for the top 3 panels
        private class TopPanel extends JPanel {
    
            private int maxLength;
            private boolean cyclic;
    
    
            public TopPanel() {
                super(true);
                initComponents();
                setOpaque(false);
                cyclic = true;
                maxLength = 0;
            }
    
    
            @Override
            public void paintComponent(Graphics g) {
                if(isOpaque()) {
                    super.paintComponent(g);
                    return;
                }
    
                int width = getWidth();
                int height = getHeight();
    
                GradientPaint paint = null;
    
                //Color top = new Color(50, 50, 50);
                //Color btm = new Color(19, 19, 19);
    
                Color top = new Color(0xFF222222);
                Color btm = new Color(0xFF0c0c0c);
    
                paint = new GradientPaint(width / 2, 0, top, width / 2, maxLength > 0 ? maxLength : height, btm, cyclic);
    
                if(paint == null) {
                    throw new RuntimeException("Invalid direction specified in GamerTagPanel");
                }
    
                Graphics2D g2d = (Graphics2D) g;
                Paint oldPaint = g2d.getPaint();
                g2d.setPaint(paint);
                g2d.fillRect(0, 0, width, height);
                g2d.setPaint(oldPaint);
    
                super.paintComponent(g);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(300, 200);
            }
    
            @Override
            public void paintBorder(Graphics g) {
                Dimension d = getSize();
    
                g.setColor(new Color(0xFF484848));
                g.drawRoundRect(1, 1, d.width-3, d.height-3, 10, 10);
    
                g.setColor(Color.BLACK);
                g.drawRoundRect(0, 0, d.width-1, d.height-1, 10, 10);
            }        
    
            private void initComponents() {
                GridBagConstraints gbc;
                JLabel jLabel1 = new JLabel();
                JLabel jLabel2 = new JLabel();
    
                setBorder(BorderFactory.createLineBorder(new Color(204,204,204)));
                setLayout(new GridBagLayout());
    
                jLabel1.setFont(new Font("Tahoma", Font.BOLD, 11));
                jLabel1.setForeground(new Color(255, 255, 255));
                jLabel1.setText("Scanning...");
                gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
                gbc.anchor = GridBagConstraints.NORTHWEST;
                gbc.insets = new Insets(5, 5, 5, 5);
                add(jLabel1, gbc);
    
                jLabel2.setFont(new java.awt.Font("Tahoma", Font.BOLD, 11));
                jLabel2.setForeground(new Color(0xFF9f9f9f));
                jLabel2.setText("C:\\Directory\\Folder\\SubFolder\\SpecificFolder\\File.file");
                gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 1;
                gbc.gridwidth = 2;
                gbc.fill = GridBagConstraints.HORIZONTAL;
                gbc.anchor = GridBagConstraints.NORTHWEST;
                gbc.weightx = 1.0;
                gbc.insets = new Insets(5, 5, 5, 5);
                add(jLabel2, gbc);
            }
        }
    
        public class MidPanel extends JPanel {
    
            private int maxLength;
            private boolean cyclic;
    
            public MidPanel() {
                setLayout(new GridBagLayout());
                setOpaque(false);
                maxLength = 0;
                cyclic = false;
            }
    
    
    //        public void paintBorder(Graphics g) {
    //            g.setColor(Color.RED);
    //            Rectangle bounds = getBounds();
    //            g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 10, 10);
    //        }
    
            @Override
            public void paintComponent(Graphics g) {
                if(isOpaque()) {
                    super.paintComponent(g);
                    return;
                }
    
                int width = getWidth();
                int height = getHeight();
    
                GradientPaint paint = null;
    
                Color top = new Color(0xFF282828);
                Color btm = new Color(0xFF0e0e0e);
    
                paint = new GradientPaint(width / 2, 0, top, width / 2, maxLength > 0 ? maxLength : height, btm, cyclic);
    
                if(paint == null) {
                    throw new RuntimeException("Invalid direction specified in GamerTagPanel");
                }
    
                Graphics2D g2d = (Graphics2D) g;
                Paint oldPaint = g2d.getPaint();
                g2d.setPaint(paint);
                g2d.fillRect(0, 0, width, height);
                g2d.setPaint(oldPaint);
                super.paintComponent(g);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(300, 400);
            }
        }
    }
    

    Best way to implement this UI

    I think the only correct approach is to implement new Look&Feel subset. Take a look on project seaglass:

    enter image description here

    What did I use

    All these examples were prepared using Inkscape -- an Open Source vector graphics editor. You can download my SVG source