【问题标题】:Custom Gradient Button - can't see Text自定义渐变按钮 - 看不到文字
【发布时间】:2011-11-23 08:54:49
【问题描述】:

我正在制作一个具有渐变效果的自定义按钮。我可以设置渐变效果,但看不到文字。我哪里错了?

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);
    }   
}  

注意:我允许用户在运行时更改颜色。根据更改为的颜色,我相应地设置了背景。

【问题讨论】:

  • 仍然没有将 super.paintComponent 移到最后...为什么不呢?
  • 不要遵循任何模糊的车道(如手动绘制文本,f.i).. 手头的任务是找出为什么我发布的解决方案(并由 Rob 检查)在您的上下文中不起作用(就像我们的一样)是时候展示一个 SSCCE 来演示您遇到的问题。我的直觉告诉我还有其他问题……

标签: java swing gradient jbutton


【解决方案1】:

正如 Stan 已经回答的那样,解决方案的一部分是

button.setOpaque(false)

按钮有点疯狂,他们想缩进真的不画背景

button.setContentAreaFilled(false)

当心:确切的结果可能仍然高度依赖 LAF - f.i.看起来真的很糟糕。对于基于合成器(如 f.i. Nimbus),您可能会考虑安装一个自定义 Painter,该 Painter 配置了用户选择的渐变/颜色

编辑

刚刚仔细检查:

// 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()
}

适用于所有核心 LAF(获胜时)

【讨论】:

  • 正如您在更新后的 cade 中所见,我实现了 setOpaque 和 setContentAreaFilled。还添加了drawString。但是无论如何该字符串是不可见的。
  • @Tvd 你还是没有把超级调用移到方法的末尾
  • 我试过了。如果我这样做,那么所有颜色变化都消失了,默认颜色就会出现。所以我再次移到顶部。
  • 我尝试将 L&F 更改为 Motif,然后在其中起作用。现在我没有使用任何drawString。非常感谢。
【解决方案2】:

设置组件 opaque=false 避免背景绘制。

调用所有渐变绘制代码并在方法结束时调用super.paintComponent()

【讨论】:

  • 我确实不透明到假。 & 在最后调用 super.paintComponents 时,它显示了正常的按钮,我表示颜色丢失了。我想保留颜色并显示文本。 “调用所有渐变绘制代码”是什么意思。
  • 显然背景以某种方式绘制。尝试检查调用 getBackground() 的位置。尝试在 super 之前将 setBackground() 设置为透明色并在之后重置。
【解决方案3】:

看起来您使用相同的 Paint 对象来绘制背景和前景,所以我猜文本只是与背景合并。

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 );

【讨论】:

  • +1 好收获!甚至没有看到他/她在做拉绳。这是错误的,我们知道 :-) 让 ui 尽可能地处理
  • 正如 kleopatra 建议的那样,甚至不应该使用 drawString() 方法。删除 drawString() 方法并在 Paint 对象恢复为原始 Paint 后添加 super.paintComponent(g) 后,海报代码对我来说很好。
  • 只是好奇..你真的需要恢复图形的状态吗? Worksforme 没有(我天生懒惰:-)
  • 你的权利!我也很懒。我懒得在测试之前删除这行代码:)
【解决方案4】:

你重写了paintComponent方法并且不调用它的超级版本。

paintComponent 负责编写实际的文本——所以如果它没有被调用,你就没有文本。

所以在这一点上:

自己编写代码来绘制标签,这可能会也可能不会复杂,具体取决于您将如何处理调整大小等

调用 super.paintComponent -- 如果它重新绘制背景可能不起作用。

【讨论】:

  • super.paintComponent 不起作用我尝试使用 & 不使用,但它无助于显示文本。您能否给我一些提示代码或示例或指导以开始编写文本。
【解决方案5】:

我认为使用paintComponent()为自定义JButton创建背景不是正确的方法,这个背景可以改变两种方式

1) 替换默认BackGround

2) 覆盖BasicButtonUIexample for MetalButtonUI,注意MetalButtonUI 仅适用于CrossPlatformLookAndFeel == MetalLookAndFeel

编辑(最好从 ButtonModel 移除/禁用镇流器)

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) {
    }
}

【讨论】:

  • mKorbel,如果用户更改颜色,我必须更改背景颜色(参见 Q 中的注释)。在这种情况下,我将能够经常替换默认背景并且会更新它。
  • mKorbel,创建了 BasicButtonUI 的子类,但它不只显示按钮。这是我实现的类:skydrive.live.com/… 那类我错在哪里。
  • @Tvd 看到我的编辑,我从你的代码中吸取了paintText,将 MetalXxxXx 更改为 BasicXxxXx,并更改了颜色(仅用于我的测试目的),我看不出有什么问题,请检查并恢复
  • 不,不,不... a) 不要自定义字符串绘制 b) 不要动态扩展 UISomething(很难做到正确,而且必须为所有支持的 LAF 完成) c) 即使对于最简单的 LAF(如 f.i. Metal),如果有 MetalSomething,也不要覆盖 BasicSomething d) 一定要让解决方案代码比问题代码更干净,毕竟你的角色是专家 回答时 ;-)
  • @mKorbel,是的,您的代码有效。但这会在水平方向上给出渐变,而我想要垂直方向。我用我的paintComponent() 代码替换了paint 的内容,它确实有效。对于文本,我调用了paintText,尽管在您的版本中您不需要调用,但我必须调用否则没有文本可见。在paint() 中,我将JComponent 转换为AbstractButton,并在调用paintText() 时像在其他绘制方法中一样传递其边界和文本。但是文本在 TopLEFT 上可见,而不是在您的绘画代码中显示的中心。为什么会有这种差异?
猜你喜欢
  • 1970-01-01
  • 2021-11-07
  • 2011-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-09
相关资源
最近更新 更多