Reputation: 99
I am trying to create a gradient paint for text that goes from the top of the word to the bottom, not from left to right. I was actually able to achieve this from the help of this link here. They took the shape of the text, and painted it on the panel. I simply edited their code and was able to apply the affect I am looking for. Here is what I edited their paint method to (where s is a Shape):
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.translate(100, 150);
Rectangle2D r = s.getBounds2D();
int x = (int) r.getX();
int y = (int) r.getY();
int h = (int) r.getHeight();
GradientPaint gp = new GradientPaint(x, y, Color.MAGENTA, x, h, Color.ORANGE);
g2.setPaint(gp);
g2.fill(s);
}
This worked, but this approach is overriding a paintComponent method of a JPanel. I am trying to recreate this by a new GradientLabel Class that extends JLabel. The issue I am having is that the g2d.fill(s)
method is drawing the shape somewhere above the label, seemingly out of reach. I don't understand why it is doing this. Perhaps its from casting Graphics2D g.create();
? I have had to add the g2.translate(x,y)
method to pull the shape down into a viewable location.
I guess I have 2 questions.
Why doesn't the g2.fill(s)
draw the shape over the text that was drawn by the JLabel super method? Could this be because of my layout manager?
Is this approach even the way I should go? Is there an easier way to apply a vertical paint gradient to text?
Here is the minimal code for testing:
public class test extends JFrame {
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
test frame = new test();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 516, 360);
contentPane = new JPanel();
contentPane.setBorder(null);
setContentPane(contentPane);
GridBagLayout gbl_contentPane = new GridBagLayout();
gbl_contentPane.columnWidths = new int[]{0, 0};
gbl_contentPane.rowHeights = new int[]{0, 100, 0};
gbl_contentPane.columnWeights = new double[]{1.0, Double.MIN_VALUE};
gbl_contentPane.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE};
contentPane.setLayout(gbl_contentPane);
Component verticalStrut = Box.createVerticalStrut(20);
GridBagConstraints gbc_verticalStrut = new GridBagConstraints();
gbc_verticalStrut.insets = new Insets(0, 0, 5, 0);
gbc_verticalStrut.gridx = 0;
gbc_verticalStrut.gridy = 0;
contentPane.add(verticalStrut, gbc_verticalStrut);
GradientLabel lblTest = new GradientLabel("TEST");
lblTest.setHorizontalAlignment(SwingConstants.CENTER);
lblTest.setGradientColors(Color.GREEN, Color.WHITE);
lblTest.setFont(new Font("Tahoma", Font.PLAIN, 70));
GridBagConstraints gbc_lblTest = new GridBagConstraints();
gbc_lblTest.fill = GridBagConstraints.BOTH;
gbc_lblTest.gridx = 0;
gbc_lblTest.gridy = 1;
contentPane.add(lblTest, gbc_lblTest);
}
public class GradientLabel extends JLabel {
private Color c1;
private Color c2;
public GradientLabel(String text) {
setText(text);
this.setOpaque(false);
}
public void setGradientColors(Color c1, Color c2) {
this.c1 = c1;
this.c2 = c2;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Font f = getFont();
GlyphVector v = f.createGlyphVector(getFontMetrics(f).getFontRenderContext(), getText());
Shape s = v.getOutline();
Rectangle2D r = s.getBounds2D();
int x = (int) r.getX();
int y = (int) r.getY();
int h = (int) r.getHeight();
int w = (int) r.getWidth();
//without this the shape is drawn almost out of view
g2d.translate(x, h);
g2d.drawRect(x, y, w, h);
//for some reason using only h as the second y doesn't show much of the second color.
//Subtracting 60 arbitrarily showed more of the second color in the gradient.
//Bonus points for an explanation on why that happens.
GradientPaint gp = new GradientPaint(x, y, c1, x, h - 60, c2);
g2d.setPaint(gp);
g2d.fill(s);
}
}
}
Upvotes: 1
Views: 221
Reputation: 99
Well I was able to answer my own question! First time for everything I guess.
I tracked the code on the JLabel back to the class where it was actually being drawn on the screen to the BasicLabelUI
Class. I studied and determined that if I could build a new class that extends this class, I could simply override the painting portion of this class. After testing and determining the best gradient that fully paints both colors from the top of the text to the bottom, this is what I came up with:
public class SBLabelUI extends BasicLabelUI {
@Override
protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
if (l instanceof GradientLabel) {
GradientLabel gl = (GradientLabel) l;
Graphics2D g2d = (Graphics2D) g;
Font f = gl.getFont();
int h = gl.getFontMetrics(f).getHeight();
GradientPaint gp = new GradientPaint(textX, textY, gl.c2, textX, Math.abs(textY-h), gl.c1);
g2d.setPaint(gp);
g2d.drawString(s, textX, textY);
} else {
super.paintEnabledText(l, g, s, textX, textY);
}
}
}
And in my Constructor for the gradient Label, i simply set the UI:
public GradientLabel(String text) {
setText(text);
this.setOpaque(false);
setUI(new SBLabelUI());
}
Upvotes: 2