改变JButton渐变色,但只针对一个按钮而非全部

14
3个回答

23

您可以重写JButton实例的paintComponent方法,并使用以下实现Paint接口的类之一来绘制其Graphics对象:


import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public final class JGradientButtonDemo {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();         
            }
        });
    }

    private static void createAndShowGUI() {
        final JFrame frame = new JFrame("Gradient JButton Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new FlowLayout());
        frame.add(JGradientButton.newInstance());
        frame.setSize(new Dimension(300, 150)); // used for demonstration
        //frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static class JGradientButton extends JButton {
        private JGradientButton() {
            super("Gradient Button");
            setContentAreaFilled(false);
            setFocusPainted(false); // used for demonstration
        }

        @Override
        protected void paintComponent(Graphics g) {
            final Graphics2D g2 = (Graphics2D) g.create();
            g2.setPaint(new GradientPaint(
                    new Point(0, 0), 
                    Color.WHITE, 
                    new Point(0, getHeight()), 
                    Color.PINK.darker()));
            g2.fillRect(0, 0, getWidth(), getHeight());
            g2.dispose();

            super.paintComponent(g);
        }

        public static JGradientButton newInstance() {
            return new JGradientButton();
        }
    }
}

在这里输入图片描述


1
由于应该是与外观和感觉有关的,但非常好+1。 - mKorbel
1
我在SO上找到的最佳解决方案 - Ray Hulha

7
一点改进意见:

enter image description here

以上内容涉及IT技术。
private static final class JGradientButton extends JButton{
    private JGradientButton(String text){
        super(text);
        setContentAreaFilled(false);
    }

    @Override
    protected void paintComponent(Graphics g){
        Graphics2D g2 = (Graphics2D)g.create();
        g2.setPaint(new GradientPaint(
                new Point(0, 0), 
                getBackground(), 
                new Point(0, getHeight()/3), 
                Color.WHITE));
        g2.fillRect(0, 0, getWidth(), getHeight()/3);
        g2.setPaint(new GradientPaint(
                new Point(0, getHeight()/3), 
                Color.WHITE, 
                new Point(0, getHeight()), 
                getBackground()));
        g2.fillRect(0, getHeight()/3, getWidth(), getHeight());
        g2.dispose();

        super.paintComponent(g);
    }
}

如何将此实现到已经包含在GUI中的按钮上?如果我将其添加到按钮上,是否需要更改操作监听器?这是否可行?或者,更好的问题是:首先询问这个问题是否合理? - Ethan Moore
如果GUI已经有一个按钮,那么必须有一些代码来创建该按钮(JButton b = new JButton("whatever"))。要替换默认按钮,您需要创建一个JGradientButton(而不是JButton b = new JGradientButton("whatever")),并将背景颜色设置为所需的颜色(b.setBackground(..somecolor...))。处理按钮的GUI中剩余的代码应保持不变。 - luca
1
例如在NetBeans的Gui Builder中,选择按钮,转到属性选项卡“代码”,更改“自定义创建代码”。 - Mark Jeronimus

2
TL;DR: 直接不可能实现,但可以像 Luca 的回答一样用变通方法解决。然而他的回答使用了不正确的渐变步骤。下面列出正确的步骤。

工作原理

在 Metal LAF 中有一个硬编码异常。如果 background 属性是 UIResource 的子类,则会被忽略* ,并使用 UI 属性 Button.gradient 中的(也是硬编码的)渐变来绘制按钮。否则,如果 background 不是 UIResource, 则直接按照该背景进行绘制。

* 除非按钮被禁用,在这种情况下没有渐变,并且使用 UIResource 中的颜色作为背景。


渐变

根据 MetalButtonUI 的逻辑,我发现它使用的渐变来自 UI 属性 Button.gradient,其中包含 ArrayList:

0 = {Float} 0.3
1 = {Float} 0.0
2 = {ColorUIResource} "[221,232,243]"
3 = {ColorUIResource} "[255,255,255]"
4 = {ColorUIResource} "[184,207,229]"

按照这个逻辑,我最终到达了MetalUtils.GradientPainter.drawVerticalGradient()。这个实现将上面的数据解释为*:

  • 从0%到30%的渐变:从color1到color2
  • 从30%到60%的渐变:从color2到color1
  • 从60%到100%的渐变:从color1到color3

*假设第二个浮点数为0.0,否则会绘制更多的渐变。

由于这是一个多阶段渐变,无法使用简单的GradientPaint来完成,但可以使用LinearGradientPaint来完成。然而,background属性只接受Color。它甚至无法被欺骗/黑客攻击,因为实际值最终被赋给Graphics.setColor()而不是Graphics2D.setPaint()(即使Metal基于Swing而不是AWT)死路一条。唯一的解决方案似乎是完全子类化JButton。


谢谢,这对于在CSS中重建按钮非常有帮助! - jobukkit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接