Java 如何使用actionListener更改JButton的颜色

Java 如何使用actionListener更改JButton的颜色,java,swing,jbutton,Java,Swing,Jbutton,我有以下JFrame。 它包含一个由正方形和圆形按钮组成的按钮[100]。我想在单击它们时更改它们的颜色。所以我使用actionListener来实现这一点。但是当我编写actionListener来更改颜色时,它给了我一个例外 线程“AWT-EventQueue-0”java.lang.ArrayIndexOutofBounds异常:索引100超出长度100的界限 它说在b[i].setBackground(Color.blue)是个例外;在actionListener内部。 我搜索了很多,

我有以下JFrame。

它包含一个由正方形和圆形按钮组成的按钮[100]。我想在单击它们时更改它们的颜色。所以我使用actionListener来实现这一点。但是当我编写actionListener来更改颜色时,它给了我一个例外

线程“AWT-EventQueue-0”java.lang.ArrayIndexOutofBounds异常:索引100超出长度100的界限

它说在b[i].setBackground(Color.blue)是个例外;在actionListener内部。 我搜索了很多,没有任何东西改变颜色,只是给出了一个例外。 这是我的密码

Subject.java

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.*;

public class Subject extends JFrame{
    public Subject() {
        super("Subject");
        p = new JPanel(new GridLayout(10,10));
        b = new JButton[100];
        Random r = new Random();
        for(i=0;i<100;i++) {
            y = r.nextInt(2) +1;
            if(y==1) {
                b[i] = new JButton();
                b[i].setBackground(Color.black);
                b[i].setPreferredSize(new Dimension(35,35));
                p.add(b[i]);
            }else {
                b[i] = new Circle();
                b[i].setBackground(Color.black);
                p.add(b[i]);
            }
            b[i].addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    b[i].setBackground(Color.blue);
                }
            }); 
        }
        add(p);
        pack();
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocation(100,200);
    }
    
    private JPanel p;
    private JButton[] b;
    private int i, y;
    
}
import java.awt.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;

public class Circle extends JButton{
    public Circle() {
        setBackground(Color.red);
        setFocusable(false);
     
        /*
         These statements enlarge the button so that it 
         becomes a circle rather than an oval.
        */
        Dimension size = getPreferredSize();
        size.width = size.height = Math.min(35,35);
        setPreferredSize(size);
     
        /*
         This call causes the JButton not to paint the background.
         This allows us to paint a round background.
        */
        setContentAreaFilled(false);
      }
     
      protected void paintComponent(Graphics g) {
        if (getModel().isArmed()) {
          g.setColor(Color.yellow);
        } else {
          g.setColor(getBackground());
        }
        g.fillOval(0, 0, getSize().width - 1, getSize().height - 1);
        JLabel l = new JLabel("Click Me");
        
        super.paintComponent(g);
      }
     
      protected void paintBorder(Graphics g) {
        g.setColor(Color.darkGray);
        g.drawOval(0, 0, getSize().width - 1, getSize().height - 1);
      }
     
      // Hit detection.
      Shape shape;
     
      public boolean contains(int x, int y) {
        // If the button has changed size,  make a new shape object.
        if (shape == null || !shape.getBounds().equals(getBounds())) {
          shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight());
        }
        return shape.contains(x, y);
      }
}
我也尝试了以下方法,但没有任何改变

b[i].addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (e.getSource()==b[i])
                    {
                        b[i].setBackground(Color.blue);
                    }
                }
            }); 

有人对如何修复它有什么建议吗?谢谢大家!

只需更改
actionPerformed()方法中的以下行即可

b[i].挫折背景(颜色.蓝色);
对此

((JButton)e.getSource()).setBackground(Color.blue);
您正在为每个
JButton
创建一个单独的匿名类(实现
ActionListener
接口)。因此,
ActionEvent
源只能是为其创建匿名类的
JButton

请注意,编译java代码后,每个
ActionListener
都有一个单独的类文件。类文件名将以
Subject$
开头,以
.class
结尾,例如:

Subject$1.class
Subject$2.class
Subject$3.class

因为您已经为每个
JButton

创建了一个类,所以至少会有100个此类,只需在
actionPerformed()
方法中更改以下行即可

b[i].挫折背景(颜色.蓝色);
对此

((JButton)e.getSource()).setBackground(Color.blue);
您正在为每个
JButton
创建一个单独的匿名类(实现
ActionListener
接口)。因此,
ActionEvent
源只能是为其创建匿名类的
JButton

请注意,编译java代码后,每个
ActionListener
都有一个单独的类文件。类文件名将以
Subject$
开头,以
.class
结尾,例如:

Subject$1.class
Subject$2.class
Subject$3.class

既然您已经为每个
JButton

创建了一个类,那么至少会有100个这样的类。您是否也可以在更改背后加入推理,以便OP(和其他读者)知道应该避免什么错误?@Abra谢谢。我从来没有想过要这样做that@knowsnothing,将至少有100个这样的类-因此更好的实现是不要为每个按钮创建唯一的ActionListener。相反,ActionListener应该在循环外部创建,然后您只需为每个按钮共享相同的ActionListener。请参阅:关于这种方法的一个工作示例。您是否也可以包括这种更改背后的原因,以便OP(和其他读者)知道应该避免什么错误?@Abra谢谢。我从来没有想过要这样做that@knowsnothing,将至少有100个这样的类-因此更好的实现是不要为每个按钮创建唯一的ActionListener。相反,ActionListener应该在循环外部创建,然后您只需为每个按钮共享相同的ActionListener。请参阅:此方法的一个工作示例。有关为什么要面向
java.lang.ArrayIndexOutOfBoundsException:Index 100
,这是因为在
b[i]处。挫折背景(Color.blue)
您使用的是
i
,这是一个类字段,循环结束后将保存值
100
,使每个侦听器都希望执行
b[100]。setBackground(…)
。现在的问题是:你们为什么要把它变成一个领域?是因为当您在
for(int i=0;…)中声明
i
时,编译器抱怨匿名类只能访问最终或有效的最终局部变量吗?为什么您要面对
java.lang.arrayindexoutofbounds异常:索引100
是因为在
b[i].setBackground(Color.blue)
您使用的是
i
,这是一个类字段,循环结束后将保存值
100
,使每个侦听器都希望执行
b[100]。setBackground(…)
。现在的问题是:你们为什么要把它变成一个领域?是因为当您在
for(int i=0;…)
编译器中声明
i
时,匿名类只能访问最终或有效的最终局部变量吗?