为什么我的所有ActionListener都以相同的循环添加到JButton?

时间:2017-03-03 01:01:45

标签: java swing

好的,所以我想尝试下棋。我有一个程序,可以创建一个JButton 8x8的二维数组。然后我在一个循环中创建它们,像在白色/黑色之间来回移动并添加动作事件。我遇到的问题是每个按钮都有相同的动作事件,它是最后创建的事件。第8行H列上的按钮是数组中所有按钮的动作侦听器。这是一段代码,我正在创建按钮并添加它们。

我还有一个Enum Columns,例如从int到character 1到H. selectPosition和targetPosition是具有两个成员列和行的对象。

public void initializeGui(boolean isWhite) {
    boolean shouldBeWhite = true;
    for(int i = 0; i< 8; i++){
        for(int j = 0; j < 8; j++){
            column = i+1;
            row = j+1;
            JButton square = new JButton();
            square.addActionListener(new ActionListener(){
                            @Override
                                public void actionPerformed(ActionEvent e) {
                                    final int thisRow = row;
                                    final int thisColumn = column;
                                    selectPosition.setColumn(Columns.getColumnsFromInt(thisColumn));
                                    selectPosition.setRow(thisRow);
                                    if(isSelecting){
                                        System.out.print("Selecting square to move. Row: " + thisRow + " Column: " +  Columns.getColumnsFromInt(thisColumn));
                                        selectPosition.setColumn(Columns.getColumnsFromInt(thisColumn));
                                        selectPosition.setRow(thisRow);
                                    } else{
                                        System.out.print("Targeting square to move to. Row: " + thisRow + " Column: " + Columns.getColumnsFromInt(thisColumn) + "\n");
                                        targetPosition.setColumn(Columns.getColumnsFromInt(thisColumn));
                                        targetPosition.setRow(thisRow);
                                    }
                                    System.out.println("");
                                isSelecting = !isSelecting;

                                }

            });
            if(shouldBeWhite){
                square.setBackground(Color.WHITE);
                shouldBeWhite = false;
            }else{
                square.setBackground(Color.BLACK);
                shouldBeWhite = true;
            }
            if (j == 7){
                shouldBeWhite = !shouldBeWhite;
            }
            chessBoardSquares[i][j] = square;
            gui.add(chessBoardSquares[i][j]);
        }
    }
    if(isWhite){
        setInitialPiecesWhiteStart();
    }else{
        setInitialPiecesBlackStart();
    }

}

作为本课程的成员,还有以下内容:

int column = 0, row = 0;

当我点击任何这些按钮时,我看到了打印

Selecting square to move. Row: 8 Column: H
Targeting square to move to. Row: 8 Column: H

Selecting square to move. Row: 8 Column: H
Targeting square to move to. Row: 8 Column: H

等等。我的问题是为什么这些按钮都被赋予相同的动作事件?我的逻辑演练就像创建第一个按钮集column = i + 1和row = j + 1然后添加一个动作侦听器,其中一个动作事件将当前行/列值设置为内部最终变量然后打印出来thisRow和thisColumn与该动作事件相关联。我是否在最后覆盖了这些值,还是我的范围错了?基本上我是如何错误地创建这些按钮动作侦听器的?

3 个答案:

答案 0 :(得分:1)

你可以......

使用actionCommand API在按钮和ActionListener ...

之间传递信息
JButton btn = new JButton();
btn.setActionCommand(row + "x" + column);
btn.addActionListener(new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        String cmd = e.getActionCommand();
        //...
    }
});

这里的问题是你依靠String解析来提取值,这可能会很快变得混乱

你可以......

创建一个自定义ActionListener,其中包含您要使用的值...

public class SquareActionListener implements ActionListener {
    private int column;
    private int row;

    public SquareActionListener(int row, int column) {
        this.row = row;
        this.column = column;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        //...
    }
}

这会将ActionListener与其余代码分离,并为您提供所需的信息,但是,您可能需要传递其他信息(例如模型)以及它的工作

你可以......

利用旨在提供自包含工作单元的Action API,它通常是一种更易于使用的解决方案,但可能会超出您现在的需求

public class SquareAction extends AbstractAction {
    private int column;
    private int row;

    public SquareAction(int row, int column) {
        this.row = row;
        this.column = column;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        //...
    }
}

这看起来很像上一个建议,但不是将其添加为按钮的ActionListener,而是直接将其应用于按钮...

JButton btn = new JButton(new SquareAction(row, column));

然后该按钮使用其他属性(我没有设置)来设置自己

答案 1 :(得分:0)

在制作一个井字游戏时我遇到了同样的问题。我使用每个按钮的哈希码来追溯实际推送的按钮。这就是我的按钮设置:

hashcodes= new ArrayList<Integer>();

    for (int i=1;i<=9;i++) {
        JButton button = new JButton();
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                setHash(button.hashCode());
                testWinner();
                testDraw();
            }
        });
        hashcodes.add(button.hashCode());
        panel.add(button);
    }
}

    private void setHash(int hashcode) {
            for (int h:hashcodes) {
                if (h==hashcode) {
                    //do stuff
                }
            }
        }

答案 2 :(得分:0)

这是我的Test课程,它完美无缺。

public class Test extends javax.swing.JFrame {

    private javax.swing.JButton[][] buttons;

    private final int ROW = 8;
    private final int COLUMN = 8;

    public Test() {
        initComponents();
    }

    private void initComponents() {
        this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        this.setExtendedState(javax.swing.JFrame.MAXIMIZED_BOTH);
        this.buttons = new javax.swing.JButton[ROW][COLUMN];
        this.setLayout(new java.awt.GridLayout(ROW, COLUMN));
        for (int i = 0; i < ROW; i++) {
            for (int j = 0; j < COLUMN; j++) {
                final int row = i;
                final int column = j;
                buttons[i][j] = new javax.swing.JButton(
                        String.format("Button %d-%d", i, j));
                buttons[i][j].addActionListener(new java.awt.event.ActionListener() {
                    @Override
                    public void actionPerformed(java.awt.event.ActionEvent e) {
                    //    System.out.println(
                    //            String.format("You have just pressed the button at row %d and column %d", row, column));
                        javax.swing.JOptionPane.showMessageDialog(
                                Test.this, String.format("You have just pressed the button at row %d and column %d", row, column));
                    }
                });
                this.add(buttons[i][j]);
            }
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Test().setVisible(true);
    }
}