Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 896
WilliamShatner Avatar asked Feb 15 '13 15:02

WilliamShatner


2 Answers

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

like image 140
Renat Gilmanov Avatar answered Sep 22 '22 11:09

Renat Gilmanov


At a pinch, this is the best I can come up with.

GradientPanels

Notes:

  1. As best I can tell, the line border color is 74,74,74. I have used a rounded border, but it has smaller radius than shown in the original example.
  2. The top color is brightened by the offset defined in code (mostly so I could see a difference!) Reduce it to 0 for colors closer to what appear and to make the line more obvious.
  3. The color of the text seems to be 249,249,249 (#F9F9F9) but I used #B9B9B9 for the top text and white for the rest.

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

class GradientPanels {

    /** An 'offset' to make gradients more obvious. 
     * Reduce to 0 for more subtle effect.  */
    static final int o = 50;
    static final Color borderColor = new Color(74,74,74);

    public static void main(String[] args) {
        Runnable r = new Runnable() {

            @Override
            public void run() {
                JPanel gui = new JPanel(new BorderLayout());

                JPanel main = new GradientPanel(o + 40, 22);
                main.setLayout(new BorderLayout(4, 4));
                JLabel lTop = new JLabel("<html><body><h1 style='color: #B9B9B9'>Up<br>Here");
                main.add(lTop, BorderLayout.PAGE_START);
                main.setBorder(new EmptyBorder(4, 4, 4, 4));

                JPanel center = new GradientPanel(o + 40, 17);
                AbstractBorder b = new CompoundBorder(
                        new LineBorder(borderColor, 1, true),
                        new EmptyBorder(6, 6, 6, 6));
                center.setBorder(b);
                LayoutManager lm = new BoxLayout(center, BoxLayout.Y_AXIS);
                center.setLayout(lm);
                main.add(center, BorderLayout.CENTER);

                addPanel(center, "Virus Shield", o);
                center.add(Box.createRigidArea(new Dimension(10, 10)));
                addPanel(center, "Auto Scan", o);
                center.add(Box.createRigidArea(new Dimension(10, 10)));
                addPanel(center, "My BitDefender", o);
                center.add(Box.createRigidArea(new Dimension(10, 50)));

                gui.add(main, BorderLayout.CENTER);

                JOptionPane.showMessageDialog(null, gui);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
        SwingUtilities.invokeLater(r);
    }

    public static void addPanel(JPanel p, String text, int offset) {
        JPanel t = new GradientPanel(offset + 28, 20);
        AbstractBorder b = new CompoundBorder(
                new LineBorder(borderColor, 1, true),
                new EmptyBorder(6, 6, 6, 6));
        t.setBorder(b);
        t.add(new JLabel("<html><body><h2 style='color: #FFFFFF'>" + text));

        p.add(t);
    }
}

class GradientPanel extends JPanel {

    Color top;
    Color btm;

    GradientPanel(int t, int b) {
        top = new Color(t, t, t);
        btm = new Color(b, b, b);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        GradientPaint gp = new GradientPaint(0f, 0f, top,
                0f, (float) getHeight(), btm);
        g2.setPaint(gp);
        g2.fillRect(0, 0, getWidth(), getHeight());
    }
}

Edit 1

The border in my fist example is still far from that seen in the desired screenshot. In this answer I create a custom border with more rounded corners (a 'speech bubble').

speech bubble

Unfortunately that example works better for entirely transparent components like JLabel. I've not had the time to look into adapting it for opaque components.

See Border with rounded corners & transparency for further discussion.

like image 24
Andrew Thompson Avatar answered Sep 21 '22 11:09

Andrew Thompson