quantum285
quantum285

Reputation: 1032

Creating a JLabel with a Gradient

I'm new to Java and I'm trying to create a heading using a JLabel and for its fill to be a gradient. I cannot get it to work and I've been trying for a while. I've been grabbing bits of come from here and other websites and cannot seem to make this work, nor make sense of other peoples more complex code that does work. Here are my two classes so far:

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EtchedBorder;
public class Test {
    public static void main(String[] args) {
        new Test().setupGUI();
    }
    public void setupGUI() {
        //set up frames and buttons etc.
            JFrame theFrame = new JFrame ("Crystal Ball");
            theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JPanel background = new JPanel();
            background.setBackground(Color.BLUE);
            background.setLayout(new BoxLayout(background, BoxLayout.PAGE_AXIS));
            theFrame.setSize(500,1000);
            DLabel heading = new DLabel("Guess a Number");
            heading.setText("GUESS A NUMBER");
            heading.setPreferredSize(new Dimension(theFrame.getWidth(),100));
            heading.setFont(new Font("Serif", Font.PLAIN, 40));
            heading.setAlignmentX(Component.CENTER_ALIGNMENT);
            //heading.setBackground(Color.YELLOW);
            heading.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
            background.add(heading);
            theFrame.getContentPane().add(background);
            theFrame.pack();
            theFrame.setVisible(true);
            //startGame();
        }
}

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.JLabel;

public class DLabel extends JLabel
{

    Dimension size = new Dimension(70, 80);

    public DLabel(String name)
    {
        this.setPreferredSize(size);
        this.setText(name);
        this.setBorder(BorderFactory.createBevelBorder(TOP, Color.white, Color.black));
        this.setOpaque(true);
    }

    public void paintComponent(Graphics g) {
      // super.paintComponent(g);  // *** commented
      Graphics2D g2d = (Graphics2D) g;
      Color color1 = Color.YELLOW;
      Color color2 = color1.brighter();
      int w = getWidth();
      int h = getHeight();
      GradientPaint gp = new GradientPaint(0, 0, color1, 0, h, color2);
      g2d.setPaint(gp);
      g2d.fillRect(0, 0, w, h);
      super.paintComponent(g); // *** added
    }

}

Upvotes: 3

Views: 2909

Answers (3)

MadProgrammer
MadProgrammer

Reputation: 347194

There is one little "trick" you can actually do, by leaving the label transparent, you can actually paint under the text by painting BEFORE you call super.paintComponent, for example...

Raindbow

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestLabel101 {

    public static void main(String[] args) {
        new TestLabel101();
    }

    public TestLabel101() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JLabel {

        public TestPane() {
            setText("Happy, Happy");
            setForeground(Color.WHITE);
            setHorizontalAlignment(CENTER);
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g.create();
            LinearGradientPaint lgp = new LinearGradientPaint(
                    new Point(0, 0), 
                    new Point(0, getHeight()), 
                    new float[]{0.142f, 0.284f, 0.426f, 0.568f, 0.71f, 0.852f, 1f}, 
                    new Color[]{Color.PINK, Color.MAGENTA, Color.BLUE, Color.GREEN, Color.YELLOW, Color.ORANGE, Color.RED});
            g2d.setPaint(lgp);
            g2d.fill(new Rectangle(0, 0, getWidth(), getHeight()));
            g2d.dispose();
            super.paintComponent(g);
        }

    }

}

nb: I should point out that this process is inefficient, as the RepaintManager will still want to paint under the component

There is another trick, but my two year old daughter wants to check to see if Santa is here ;)

Updated

The other trick involves understanding how the paint process actually works. When you call super.paintComponent, it calls the update method on the ComponentUI (look and feel delegate), this is actually the method that fills the background if the component is opaque, this method then calls the look and feels delegate's paint method, which actually does the base painting...

We can circumvent the process slightly and instead of calling super.paintComponent, we can call the look and feels delegate's paint method directly...

public class TestPane extends JLabel {

    public TestPane() {
        setText("Happy, Happy");
        setForeground(Color.WHITE);
        setHorizontalAlignment(CENTER);
        setOpaque(true);
    }

    @Override
    protected void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        LinearGradientPaint lgp = new LinearGradientPaint(
                new Point(0, 0), 
                new Point(0, getHeight()), 
                new float[]{0.142f, 0.284f, 0.426f, 0.568f, 0.71f, 0.852f, 1f}, 
                new Color[]{Color.PINK, Color.MAGENTA, Color.BLUE, Color.GREEN, Color.YELLOW, Color.ORANGE, Color.RED});
        g2d.setPaint(lgp);
        g2d.fill(new Rectangle(0, 0, getWidth(), getHeight()));
        g2d.dispose();
        getUI().paint(g, this);
    }

}

This is more efficient then the previous example, as it doesn't require the RepaintManager to paint the area underneath this component, but it might not work with all look and feels

Upvotes: 4

camickr
camickr

Reputation: 324108

The problem is that you made the JLabel opaque, which means it will paint the background. So the call to super.paintComponent(...) over paints the gradient background. So get rid of:

//this.setOpaque(true);

Another problem with the code is that color1.brighter() doesn't work. Try something like:

  Color color2 = Color.RED;

Also, You should not change the Graphics object, since that object is also used to paint other Swing components. Instead you should use g.create() to get a copy of the Graphics object. Make your changes to that object, do the painting and then dispose() the object.

So the (untested) code would be something like:

Graphics2D g2d = (Graphics2D)g.create();
...
g2d.fillRect(...);
g2d.dispose();

super.paintCompoenent(g);

Upvotes: 3

ControlAltDel
ControlAltDel

Reputation: 35011

You should set your gradientPaint object to your Graphics and then pass that into super.paintComponent

try this:

public void paintComponent(Graphics g) {
      Graphics2D g2d = (Graphics2D) g;
      Color color1 = Color.YELLOW;
      Color color2 = color1.brighter();
      int w = getWidth();
      int h = getHeight();
      GradientPaint gp = new GradientPaint(0, 0, color1, 0, h, color2);
      g2d.setPaint(gp);
      super.paintComponent(g2d);
    }

Upvotes: 2

Related Questions