0

I am making a custom button with a gradient effect. I am able to set the gradient effect but I can't see the text. Where am I going wrong?

class CustomButton extends JButton {   
    Color color1, color2;   

    public CustomButton(String text, Color color1, Color color2) {   
        super(text);   
        this.color1 = color1;   
        this.color2 = color2;   
        setOpaque(false);   
        setSize(new Dimension(450, 350));
        setForeground(Color.white);
        setText(text);
        setContentAreaFilled(false);
    }   

    protected void paintComponent(Graphics g) {    
        super.paintComponent(g);
        int width = getWidth();   
        int height = getHeight();   

        GradientPaint paint = new GradientPaint(0, 0, color1, width, height,
                color2, true);
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);   
        Paint oldPaint = g2d.getPaint();
        g2d.setPaint(paint);
        g2d.fillRect(0, 0, width, height);
        g2d.drawString("Button 1", getWidth()/2, 10);
        g2d.setPaint(oldPaint);
    }   
}  

NOTE: I allow the user to change the colors at run time. Based on the color that was changed to, I set the background accordingly.

APerson
  • 8,140
  • 8
  • 35
  • 49
Tvd
  • 4,463
  • 18
  • 79
  • 125
  • still not moved the super.paintComponent to the end ... why not? – kleopatra Nov 23 '11 at 16:38
  • dont follow any murky lanes (as drawing text manually, f.i) .. The task at hand is to find out why the solutions posted by me (and checked by Rob) isn't working in your context (as it is in ours) Time to show a SSCCE demonstrating the problem as you experience it. My gut tells me something else is wrong ... – kleopatra Nov 23 '11 at 17:12

5 Answers5

5

as Stan already answered, one part of the solution is to

button.setOpaque(false)

buttons are a bit crazy, they want to be huddled into really not painting the background

button.setContentAreaFilled(false)

Beware: the exact outcome might still be highly LAF dependent - f.i. looking really bad. For synth-based (as f.i. Nimbus) you might consider to install a custom Painter configured with the gradient/colors as choosen by the user

Edit

just double-checked:

// tell ui to not paint the background
button.setOpaque(false);
button.setContentAreaFilled(false);

// override paintComponent
protected void paintComponent(...) {
     // do custom backgroudn painting
     ...
     // let ui handle the foreground (it wont touch the background due to the false settings above)
     super.paintComponent()
}

works fine for all core LAFs (on win)

kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • As you can see in the updated cade, I implmented setOpaque and setContentAreaFilled. Also added drawString. But yet the string is not visible in any case. – Tvd Nov 23 '11 at 11:28
  • @Tvd you still didn't move the super call to the end of the method – kleopatra Nov 23 '11 at 11:30
  • I tried that. If I do that then all color changes are gone and the default color comes. So I again shifted to top. – Tvd Nov 23 '11 at 16:41
  • I tried changing the L&F to Motif & then where it does work. Now am not using any drawString. Thanks a lot. – Tvd Nov 23 '11 at 17:48
4

Set component opaque=false to avoid background painting.

Call all your gradient paint code and call super.paintComponent() in the end of method.

StanislavL
  • 56,971
  • 9
  • 68
  • 98
  • I did opaque to false. & On calling super.paintComponents in the end, it shows the normal button I mena the coloring is lost. I want to keep the coloring and also show the text. What do you mean by "Call all your gradient paint code ". – Tvd Nov 23 '11 at 09:23
  • Obviously background somehow painted. Try to check where getBackground() is called. Try to setBackground() to transparent color before super and reset after. – StanislavL Nov 23 '11 at 09:30
3

Looks like you are using the same Paint object to paint the background and foreground, so I'm guessing the text just merges in with the background.

Paint oldPaint = g2d.getPaint();  
g2d.setPaint(paint);  
g2d.fillRect(0, 0, width, height);  
g2d.setPaint( oldPaint ); // try adding this
g2d.drawString("Button 1", getWidth()/2, 10);
//g2d.setPaint( oldPaint );
camickr
  • 321,443
  • 19
  • 166
  • 288
  • +1 good catch! Didn't even see that s/he's doing the drawString. Which is wrong, as we know :-) Let the ui handle as much as possible – kleopatra Nov 23 '11 at 16:36
  • As kleopatra suggested, the drawString() method should not even be used. The posters code works fine for me when the drawString() method is removed and the `super.paintComponent(g)` is added after the Paint object has been restored to the original Paint. – camickr Nov 23 '11 at 16:57
  • 1
    just curious .. you really need to restore the graphic's state? Worksforme without (I'm born lazy :-) – kleopatra Nov 23 '11 at 17:01
  • 1
    Your right! I too am lazy. I was too lazy to delete the line of code before testing :) – camickr Nov 23 '11 at 21:02
0

You override the paintComponent method and don't call the super version of it.

paintComponent is responsible for writing the actual text -- so if it doesn't get called no text for you.

So at this point either:

Write the code to paint the label yourself, which may or may not be complicated depending on how you will handle resizing, etc

Call super.paintComponent -- which may not work if it repaints the background.

tomjen
  • 3,779
  • 3
  • 29
  • 35
  • super.paintComponent doesn't work I tried with & without but yet it doesn't help show text. Can you please give me some hintline code or example or guidance to start with writing the text. – Tvd Nov 23 '11 at 09:21
0

I think that isn't correct way to create the BackGround for Custom JButton by using paintComponent(), this BackGround is possible to change two way

1) replace default BackGround

2) override BasicButtonUI, example for MetalButtonUI, notice MetalButtonUI works only on CrossPlatformLookAndFeel == MetalLookAndFeel

EDIT (better would be remove/disable balast from ButtonModel)

enter image description here

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.plaf.metal.MetalButtonUI;

public class TextAreaInButton {

    private JFrame frame = new JFrame("sssssssss");
    private JButton tip1Null = new JButton(" test button ");

    public TextAreaInButton() {
        Border line, raisedbevel, loweredbevel, title, empty;
        line = BorderFactory.createLineBorder(Color.black);
        raisedbevel = BorderFactory.createRaisedBevelBorder();
        loweredbevel = BorderFactory.createLoweredBevelBorder();
        title = BorderFactory.createTitledBorder("");
        empty = BorderFactory.createEmptyBorder(1, 1, 1, 1);
        final Border compound;
        Color crl = (Color.blue);
        compound = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl));
        Color crl1 = (Color.red);
        final Border compound1;
        compound1 = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl1));
        Color crl2 = (Color.black);
        final Border compound2;
        compound2 = BorderFactory.createCompoundBorder(empty, new OldRoundedBorderLine(crl2));
        tip1Null.setFont(new Font("Serif", Font.BOLD, 14));
        tip1Null.setForeground(Color.darkGray);
        tip1Null.setPreferredSize(new Dimension(50, 30));
        tip1Null.addActionListener(new java.awt.event.ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
            }
        });
        tip1Null.setBorderPainted(true);
        tip1Null.setFocusPainted(false);
        tip1Null.setBorder(compound);
        tip1Null.setHorizontalTextPosition(SwingConstants.CENTER);
        tip1Null.setVerticalTextPosition(SwingConstants.BOTTOM);
        tip1Null.setUI(new ModifButtonUI());

        tip1Null.getModel().addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                ButtonModel model = (ButtonModel) e.getSource();
                if (model.isRollover()) {
                    tip1Null.setBorder(compound1);
                } else {
                    tip1Null.setBorder(compound);
                }
                if (model.isPressed()) {
                    tip1Null.setBorder(compound2);
                }
            }
        });
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(tip1Null, BorderLayout.CENTER);
        frame.setLocation(150, 150);
        frame.setPreferredSize(new Dimension(310, 75));
        frame.setLocationRelativeTo(null);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                TextAreaInButton taib = new TextAreaInButton();
            }
        });
    }
}

class OldRoundedBorderLine extends AbstractBorder {

    private final static int MARGIN = 5;
    private static final long serialVersionUID = 1L;
    private Color color;

    OldRoundedBorderLine(Color clr) {
        color = clr;
    }

    public void setColor(Color clr) {
        color = clr;
    }

    @Override
    public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
        ((Graphics2D) g).setRenderingHint(
                RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setColor(color);
        g.drawRoundRect(x, y, width, height, MARGIN, MARGIN);
    }

    @Override
    public Insets getBorderInsets(Component c) {
        return new Insets(MARGIN, MARGIN, MARGIN, MARGIN);
    }

    @Override
    public Insets getBorderInsets(Component c, Insets insets) {
        insets.left = MARGIN;
        insets.top = MARGIN;
        insets.right = MARGIN;
        insets.bottom = MARGIN;
        return insets;
    }
}

class ModifButtonUI extends BasicButtonUI {

    //private static final ModifButtonUI buttonUI = new ModifButtonUI();

    ModifButtonUI() {
    }

    public static ComponentUI createUI(JComponent c) {
        return new ModifButtonUI();
    }

    @Override
    public void paint(Graphics g, JComponent c) {
        //final Color color1 = new Color(230, 255, 255, 0);
        //final Color color2 = new Color(255, 230, 255, 64);
        final Color color1 = new Color(00, 0, 200, 0);
        final Color color2 = new Color(255, 230, 255, 64);
        final Color alphaColor = new Color(00, 200, 230, 64);
        final Color color3 = new Color(
                alphaColor.getRed(), alphaColor.getGreen(), alphaColor.getBlue(), 0);
        final Color color4 = new Color(
                alphaColor.getRed(), alphaColor.getGreen(), alphaColor.getBlue(), 64);
        super.paint(g, c);
        Graphics2D g2D = (Graphics2D) g;
        GradientPaint gradient1 = new GradientPaint(
                0.0F, (float) c.getHeight() / (float) 2, color1, 0.0F, 0.0F, color2);
        Rectangle rec1 = new Rectangle(0, 0, c.getWidth(), c.getHeight() / 2);
        g2D.setPaint(gradient1);
        g2D.fill(rec1);
        GradientPaint gradient2 = new GradientPaint(
                0.0F, (float) c.getHeight() / (float) 2, color3, 0.0F, c.getHeight(), color4);
        Rectangle rec2 = new Rectangle(0, c.getHeight() / 2, c.getWidth(), c.getHeight());
        g2D.setPaint(gradient2);
        g2D.fill(rec2);
    }

    @Override
    protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) {
        Font f = b.getFont();
        g.setFont(f);
        FontMetrics fm = g.getFontMetrics(f);

        if (b.isEnabled()) {
            g.setColor(b.getForeground());
            g.drawString(text, textRect.x, textRect.y + fm.getAscent());
        } else {
            g.setColor(b.getBackground().brighter());
            g.drawString(text, textRect.x, textRect.y + fm.getAscent());
            g.setColor(b.getBackground().darker());
            g.drawString(text, textRect.x + 1, textRect.y + fm.getAscent() + 1);

        }
    }

    @Override
    public void paintButtonPressed(Graphics g, AbstractButton b) {
        paintText(g, b, b.getBounds(), b.getText());
        g.setColor(Color.red.brighter());
        g.fillRect(0, 0, b.getSize().width, b.getSize().height);
    }

    public void paintBorder(Graphics g) {
    }

    @Override
    protected void paintFocus(Graphics g, AbstractButton b,
            Rectangle viewRect, Rectangle textRect, Rectangle iconRect) {
    }
}
Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • mKorbel, I got to change color of background if user changes the color (See NOTE in Q). In that case will I be able to replace default Background often and will it be updated. – Tvd Nov 23 '11 at 09:52
  • mKorbel, created a subclass of BasicButtonUI, but that doesn't show the button only. Here's the class that I implemented : https://skydrive.live.com/?cid=572d7026b8b4c709&sc=documents&uc=1&id=572D7026B8B4C709%21168# Where am I wrong in that class. – Tvd Nov 23 '11 at 11:31
  • @Tvd see my edit, I suck paintText from your code, change MetalXxxXx to BasicXxxXx, and change Color (just for my testing purposes), I can't see there something wrong, please check and revert – mKorbel Nov 23 '11 at 11:54
  • 1
    no, no, no ... a) don't do custom string drawing b) don't extend UISomething on the fly (it's hard to get it right plus must be done for all supported LAFs) c) even for the most simple LAFs (as f.i. Metal), don't override BasicSomething if there's a MetalSomething d) do keep solution code _cleaner_ than problem code, after all you are in the role of _expert_ when answering ;-) – kleopatra Nov 23 '11 at 12:31
  • @mKorbel, Yes your code worked. But that gives gradient horizontally & I want vertically. I replaced the contents of paint with my paintComponent() code and it did work. For text, I called paintText though in your version you need not call but I got to call else NO TEXT is visible. In paint() I cast JComponent to AbstractButton and pass its Bounds & text as you do in other paint methods while calling paintText(). BUT THE TExt is visible on TopLEFT and not in the Center which it shows in your paint code. WHy is this difference ? – Tvd Nov 23 '11 at 16:50