I attempted to replicate this component (at the bottom of the post), but I can't seem to get it to look nice.
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.
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.
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.
Basically the following elements can be found behind that design:
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):
I've used the following colors:
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:
What did I use
All these examples were prepared using Inkscape -- an Open Source vector graphics editor. You can download my SVG source
At a pinch, this is the best I can come up with.
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.#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());
}
}
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').
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With