简体   繁体   English

更改按钮颜色onclick而不使用最终修改器

[英]Change button color onclick without final modifier

Consider the following code, used to change the color of a button when it is clicked. 请考虑以下代码,用于在单击按钮时更改按钮的颜色。

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

    }
}

It doesn't work, because of this error: 它不起作用,因为这个错误:

Cannot refer to the non-final local variable defined in an enclosing scope 无法引用封闭范围中定义的非最终局部变量

How can I do this without mark the button as final? 如何在不将按钮标记为最终的情况下执行此操作?

One solution would be to get the JButton's reference from the ActionEvent parameter: 一种解决方案是从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);
        }

Also you could make button a field, not a local variable. 您也可以将按钮设为字段,而不是局部变量。
Also you could declare it as final. 你也可以宣布它为最终版。

Note that you'd never use code such as what you're posting since most non-trivial GUI programs would not be created inside of a static main method as you're doing, but rather would be done within OOP-compliant GUI classes. 请注意,您永远不会使用诸如您发布的内容之类的代码,因为大多数非平凡的GUI程序都不会像您一样在静态主方法中创建,而是在符合OOP的GUI类中完成。

For example: 例如:

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

Edit regarding further questions of yours: 关于您的其他问题的修改

Actually the code in my question it's only an example, the real code is something like your. 实际上我的问题中的代码只是一个例子,真正的代码就像你的。

Then better to show the real code, or best a minimal compilable runnable example that simulates the real code. 然后更好地显示真实代码,或最好的模拟真实代码的最小可编译runnable示例。

(a) It is preferred to use e.getSource() or to make button a field? (a)最好使用e.getSource()或将按钮设为字段?

Either or. 两者任一。 If the same Action is to be used on multiple buttons, and you are only interested in the button pressed, then use getSource() . 如果要在多个按钮上使用相同的Action,并且您只对按下的按钮感兴趣,则使用getSource() If your Action or ActionListener is an inner class, then a field would work fine. 如果您的Action或ActionListener是一个内部类,那么一个字段可以正常工作。 If not, then you could pass the variable into the Action via a constructor parameter as per another answer to your question. 如果没有,那么您可以根据问题的另一个答案通过构造函数参数将变量传递给Action。

(b) You say that Also you could declare it as final but I receive this error: The local variable may not have been initialized. (b)你说那也是你可以声明它是最终但我收到这个错误:局部变量可能没有被初始化。 What I'm wrong? 我错了什么?

Without your real code, it's hard to tell, but likely you don't initialize the button at the same time that you declare it. 如果没有真正的代码,很难说,但很可能你没有在声明它的同时初始化按钮。

(c) I my GUI program I don't launch the frame from a thread (id est I write the code of createAndShowGui() in the main(), without the thread). (c)我的GUI程序我没有从线程启动框架(id est我在main()中编写createAndShowGui()的代码,没有线程)。 What is the difference? 有什么区别?

My code guarantees that my GUI will start up on the Swing event thread, something that should be done for thread safety. 我的代码保证我的GUI将在Swing事件线程上启动,这应该是为了线程安全。

You can give the Button as a constructor parameter to the listener. 您可以将Button作为构造函数参数提供给侦听器。

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

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

And use it like: 并使用它像:

button.addActionListener(new ButtonColorAction(button));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM