0

As the title would suggest, I am trying to duplicate the text underneath the main text on a JButton, and move it down by one pixel. I'm trying to get a drop-shadow like effect on it, without the blur, and one pixel directly under the text.

How would I do this, and would it be easier to just set a JPanel with an actionListener rather than a button?

Code -

import java.awt.Color;
import java.awt.Component;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;

import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;

class ButtonUI extends JButton {

    private Color startColor = new Color(162, 110, 235);
    private Color endColor = new Color(110, 49, 237);
    private Color rollOverTopColor = new Color(171, 137, 219);
    private Color rollOverBottomColor = new Color(129, 89, 216);

    private Color pressedStartColor = new Color(73, 30, 113);
    private Color pressedMidColor = new Color(113, 57, 221);
    private Color pressedEndColor = new Color(93, 43, 198);

    private Color outerBorderColor = new Color(117, 14, 182);
    private Color innerBorderTopColor = new Color(178, 133, 237, 255);
    private Color innerBorderBottomColor = new Color(178, 133, 237, 150);

    /**
     * @param top
     *            , left, bottom, right
     */
    private Insets insetsForButtons = new Insets(0, 13, 4, 13);

    private int outerRoundRectSize = 4;
    private int innerRoundRectSize = 2;
    private GradientPaint GP;

    /**
     * 
     * @param text
     */
    public ButtonUI(String text) {
        super();
        setText(text);
        setAlignmentX(Component.CENTER_ALIGNMENT);
        setContentAreaFilled(false);
        setBorderPainted(false);
        setForeground(Color.WHITE);
        setFocusable(false);
        setMargin(insetsForButtons);

    }

    /**
     * 
     * @param startColor
     * @param endColor
     * @param rollOverColor
     * @param rollOverTopColor
     * @param rollOverBottomColor
     * @param pressedColor
     * @param pressedTopColor
     * @param pressedBottomColor
     */
    public ButtonUI(Color startColor, Color endColor, Color rollOverTopColor,
            Color rollOverBottomColor, Color pressedStartColor,
            Color pressedMidColor, Color pressedEndColor) {
        super();
        this.startColor = startColor;
        this.endColor = endColor;
        this.pressedStartColor = pressedStartColor;
        this.pressedMidColor = pressedMidColor;
        this.pressedEndColor = pressedEndColor;

        setForeground(Color.WHITE);
        setFocusable(false);
        setContentAreaFilled(false);
        setBorderPainted(false);
    }

    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        int h = getHeight();
        int w = getWidth();
        ButtonModel model = getModel();
        if (!model.isEnabled()) {
            setForeground(Color.BLACK);
            GP = new GradientPaint(0, 0, new Color(73, 30, 113), 0, h,
                    new Color(73, 30, 113), true);
        } else {
            setForeground(Color.WHITE);
            if (model.isRollover()) {
                GP = new GradientPaint(0, 0, rollOverTopColor, 0, h,
                        rollOverBottomColor, true);
            } else {
                GP = new GradientPaint(0, 0, startColor, 0, h, endColor, true);
            }
        }
        g2d.setPaint(GP);
        GradientPaint p1;
        GradientPaint p2;
        if (model.isPressed()) {
            GP = new GradientPaint(0, 0, pressedStartColor, 0, h,
                    pressedMidColor, true);
            g2d.setPaint(GP);
            p1 = new GradientPaint(0, 0, outerBorderColor, 0, h - 1,
                    outerBorderColor);

            // BE SURE TO EDIT TO MAKE LESS DRAMATIC
            p2 = new GradientPaint(0, 1, innerBorderTopColor, 0, h - 3,
                    innerBorderTopColor);
        } else {
            p1 = new GradientPaint(0, 0, outerBorderColor, 0, h - 1,
                    outerBorderColor);

            p2 = new GradientPaint(0, 1, innerBorderTopColor, 0, h - 3,
                    innerBorderBottomColor);

            GP = new GradientPaint(0, 0, startColor, 0, h, endColor, true);
        }
        RoundRectangle2D.Float r2d = new RoundRectangle2D.Float(0, 0, w - 1,
                h - 1, outerRoundRectSize, outerRoundRectSize);
        Shape clip = g2d.getClip();
        g2d.clip(r2d);
        g2d.fillRect(0, 0, w, h);
        g2d.setClip(clip);
        g2d.setPaint(p1);
        g2d.drawRoundRect(0, 0, w - 1, h - 1, outerRoundRectSize,
                outerRoundRectSize);
        g2d.setPaint(p2);
        g2d.drawRoundRect(1, 1, w - 3, h - 3, innerRoundRectSize,
                innerRoundRectSize);
        g2d.dispose();

        super.paintComponent(g);
    }
}

public class ButtonClass {

    public static void createGUI() {
        JFrame programFrame = new JFrame("Custom Button UI");
        ButtonUI testButton = new ButtonUI("Custom JButton UI!");

        programFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        programFrame.add(testButton);
        programFrame.pack();
        programFrame.setVisible(true);
        programFrame.setResizable(true);
        programFrame.setSize(250, 75);
        programFrame.setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createGUI();
            }
        });
    }
}

And as usual, if you downvote this, explain what I can do better, so it won't happen again.

EDIT: posted my overrided JButton class, which is what I use for all of my buttons, rather than making this for each button.

Hathor
  • 187
  • 1
  • 2
  • 10

1 Answers1

1

You'll need to address two issues:

  • A button's text is rendered by its UI delegate; a custom ButtonUI is shown here.

  • A drop shadow can be rendered in any of a variety of ways.

Addendum: Absent an sscce in your update, I'm not sure what's not working the way you want. Instead of a custom UI delegate, you might experiment with an implementation of Icon that renders the text as either plain or shadowed. Use the setRolloverIcon() method, shown here, to change icons as desired. This LayoutTest may help with the geometry.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Sorry for taking so long to reply, I've finished a couple of edits to the program in question. I'll post the source to that above. It's possible to add said effect to the code above, correct? – Hathor Jun 29 '13 at 02:24
  • Edited with an SSCCE. The only thing that's not working with what I want is duplicating the text under the current text, changing the color, and shifting it down one pixel. The reason I'm not using images is because rather than saving separate images for every single button, making a CustomUI delegate would achieve roughly the same effect with more control. – Hathor Jun 29 '13 at 14:11
  • You can't just create a class named `ButtonUI`; you have to subclass one of the concrete implementations of `javax.swing.plaf.ButtonUI`. If you go my way, don't use images; implement `Icon` to render the text, for [example](http://stackoverflow.com/a/2834484/230513). – trashgod Jun 29 '13 at 14:55