Java 在不使用最终修改器的情况下更改按钮颜色

Java 在不使用最终修改器的情况下更改按钮颜色,java,swing,user-interface,jbutton,local-variables,Java,Swing,User Interface,Jbutton,Local Variables,考虑以下代码,用于在单击按钮时更改按钮的颜色 import java.awt.Color; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JFrame; public class ChangeColor { public static void main(String[] args) {

考虑以下代码,用于在单击按钮时更改按钮的颜色

import java.awt.Color;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;

public class ChangeColor {

    public static void main(String[] args) {

        JButton button = new JButton();
        button.setBackground(Color.BLUE);

        button.addActionListener(new AbstractAction() {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                button.setBackground(Color.RED);

            }
        });

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(button);
        frame.setSize(200, 200);
        frame.setVisible(true);

    }
}
由于以下错误,它无法工作:

无法引用在封闭范围中定义的非最终局部变量


如何在不将按钮标记为final的情况下执行此操作?

您可以将按钮作为构造函数参数提供给侦听器

class ButtonColorAction extends AbstractAction {
  private JButton button;
  public ButtonColorAction(JButton button) {
    this.button = button;
  }

  @Override
  public void actionPerformed(ActionEvent e) {
    button.setBackground(Color.RED);
  }
}
然后像这样使用它:

button.addActionListener(new ButtonColorAction(button));

一种解决方案是从ActionEvent参数获取JButton的引用:

        @Override
        public void actionPerformed(ActionEvent e) {
            // the source here refers to the object that provoked this method to occur
            JButton sourceBtn = (JButton) e.getSource();
            sourceBtn.setBackground(Color.RED);
        }
您还可以将按钮设置为字段,而不是局部变量。
你也可以宣布它为最终版本

请注意,您永远不会使用所发布的代码,因为大多数非平凡的GUI程序不会像您所做的那样在静态主方法中创建,而是在符合OOP的GUI类中创建

例如:

import java.awt.Color;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class ButtonColorChange extends JPanel {
    private JButton button = new JButton(new ButtonAction("Press Me"));

    public ButtonColorChange() {
        add(button);
    }

    private static void createAndShowGui() {
        JFrame frame = new JFrame("ButtonColorChange");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new ButtonColorChange());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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

class ButtonAction extends AbstractAction {
    private static final Color COLOR_1 = Color.BLUE;
    private static final Color COLOR_2 = Color.RED;

    public ButtonAction(String name) {
        super(name);
        int mnemonic = (int) name.charAt(0);
        putValue(MNEMONIC_KEY, mnemonic);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        AbstractButton btn = (AbstractButton) e.getSource();
        Color c = btn.getBackground();
        c = c == COLOR_1 ? COLOR_2 : COLOR_1;
        btn.setBackground(c);
    }
}

编辑关于您的进一步问题:

实际上,我问题中的代码只是一个例子,真正的代码类似于你的

然后最好显示真实代码,或者最好是模拟真实代码的最小可编译可运行示例

(a) 最好使用e.getSource()或将按钮设置为字段

非此即彼。如果要在多个按钮上使用相同的操作,并且您只对按下的按钮感兴趣,那么请使用
getSource()
。如果您的Action或ActionListener是一个内部类,那么字段可以正常工作。如果没有,那么您可以根据问题的另一个答案,通过构造函数参数将变量传递到操作中

(b) 您说您也可以将其声明为final,但我收到了这个错误:局部变量可能尚未初始化。我怎么了

如果没有真正的代码,很难判断,但很可能在声明按钮的同时没有初始化按钮

(c) 我的GUI程序我不从线程启动框架(id est我在main()中编写createAndShowGui()的代码,没有线程)。有什么区别


我的代码保证我的GUI将在Swing事件线程上启动,这是为了线程安全应该做的。

谢谢,非常全面的响应。实际上,我问题中的代码只是一个例子,真正的代码类似于你的。我还有几个问题:(a)最好使用
e.getSource()
或将按钮设为字段?(b) 您说您也可以将其声明为final,但我收到了以下错误:
局部变量可能尚未初始化
。我怎么了?(c) 我的GUI程序我不从线程启动框架(id est我在
main()
中编写
createAndShowGui()
的代码,没有线程)。有什么区别?