【问题标题】:How would I add an action listener to buttons on a loop?如何将动作侦听器添加到循环上的按钮?
【发布时间】:2015-06-29 09:17:28
【问题描述】:

我希望每次在我的 4x4 网格中按下按钮时,它都会将 moves 增加 1 。这是创建一个 4x4 的按钮布局。每次按下这些按钮中的任何一个时,我都希望 moves 增加。基本上我正在创建记忆游戏,您可以在其中翻转卡片以相互匹配。我只需要计算一个玩家为解决这个难题所做的moves 的总数。

private int moves = 0;

private GridPane makeGridPane(){
    ConcentrationModel c = new ConcentrationModel();
    GridPane grid = new GridPane();

    ColumnConstraints col1 = new ColumnConstraints();
    col1.setPercentWidth( 50 );

    grid.getColumnConstraints().addAll(col1, col1, col1, col1);
    RowConstraints row1 = new RowConstraints();
    row1.setPercentHeight( 50 );
    grid.getRowConstraints().addAll(row1, row1, row1, row1);


    for(int row = 0; row < 4; row ++){
        for(int col = 0; col < 4; col++){
            Button btn = new Button();
            ImageView image = new ImageView(c.getCards().get(0).getImage());
            image.setFitWidth(WIDTH/4);
            image.setFitHeight(HEIGHT/4);
            btn.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
            btn.setGraphic(image);
            grid.add(btn, col, row);


        }
    }
    return grid;
}

【问题讨论】:

  • 只是为了制作我的 4x4 按钮板
  • 所以他需要开发一个事件处理程序来增加移动并链接到每个按钮单击的事件?
  • @FatFockFrank ...请忽略我的 cmets。我正在阅读另一个关于如何使用运算符的问题,并在此处意外地选项卡,然后没有完全重新阅读该问题。

标签: java button javafx


【解决方案1】:

您可以创建单个事件处理程序并将其重用于所有按钮。由于您可能还希望按钮执行其他操作,因此我建议将其添加为事件处理程序,而不是使用便捷方法 setOnAction(...)

EventHandler<ActionEvent> incrementMovesHandler = e -> moves++ ;

for(int row = 0; row < 4; row ++){
    for(int col = 0; col < 4; col++){
        Button btn = new Button();
        btn.addEventHandler(ActionEvent.ACTION, incrementMovesHandler);
        // ...
    }
}

【讨论】:

  • ...我得说,尽管该语法 (= e -&gt; moves++ ;) 完全有效,但它看起来很奇怪。不过,非常好的解决方案。我不敢说它比我的好,因为从功能上讲,它们都是等效的(AFAIK),但仍然非常干净。
  • 只是您习惯的那些事情之一...我已经为我们的内部应用程序使用 Java 8 语法大约 18 个月了(从 Java 8 ea 版本开始);很久以前,这种语法开始感觉很自然。 AIUI,它们在底层并不完全等同:例如,您的代码将编译一个附加类。 (试试看生成的类文件。)
【解决方案2】:

这其实很简单。您所要做的就是在您的grid.add(...) 之前添加这段代码:

btn.setOnAction(new EventHandler<ActionEvent>() {
    @Override public void handle(ActionEvent event) {
        moves++;
    }
});

或者,等效地,Java 8 版本:

btn.setOnAction((ActionEvent e) -> {moves++;});

(我目前无法对此进行测试,但它应该工作。如果没有,请告诉我,我会尝试修复它。)

如果您担心内存问题,Christian points out below 会为每个按钮创建一个 EventHandler 的新实例。虽然这可能不是太糟糕,但这可能是一个坏习惯。最好的处理方式(没有双关语)是在你的 for 循环之前创建一个对象:

EventHandler<ActionEvent> eh = new EventHandler<>() {
    @Override public void handle(ActionEvent event) {
        moves++;
    }
};

然后,对于每个按钮,而不是最顶层的代码,您只需编写:

btn.setOnAction(eh);

这样,一个EventHandler 将被创建并用于处理所有事件。如果您需要创建的不仅仅是几个按钮,您会想要使用这个,因为它更快(不需要为每个对象分配内存)和内存效率更高(......它,呃,不'不需要为每个对象分配内存)。在这种情况下,我认为这很微不足道,但还是很高兴知道。

【讨论】:

  • 谢谢,但我对java.awt.event.ActionListener 有点困惑。因为我正在实现 JavaFX,但不是 awtJava Swing?
  • @FatFockFrank ...我是个聪明的 cookie。 AWT 实际上两者都不是,但我需要检查 JavaFX 是如何做到的。给我一点时间来谷歌。
  • 这是一个有点昂贵的解决方案,因为您必须创建 4x4 的 EventHandler 实例来处理相同的事件。父类可以实现该功能。因此,如果您将按钮增加到 16x16,那么这将变得更加昂贵。
  • 嘿,谢谢您的时间。虽然这确实解决了增加我的moves 变量的解决方案,但我认为它会改变我在板上labelMoves = new Label(moves + " moves");hbox.getChildren().add(labelMoves); 上的标签。一旦我把这个标签放在HBox 中,当我按下按钮时它不会改变吗?
  • @FatFockFrank 你会想问另一个问题——虽然我可以给你答案,但当有人用谷歌搜索“用变量更新标签”时会发生什么,他们什么也没得到,尽管它在这里得到了回答?出于这个原因,这里不鼓励所谓的“变色龙问题”。
【解决方案3】:

你需要在你的类中实现ActionListener 接口。 然后在actionPerformed 函数中,只增加moves 变量。 您只需为每个按钮调用btn.addActionListener(this); 你创造的。

public class Sample extends JFrame implements ActionListener {

  public Sample ()
  {

  }


  private GridPane makeGridPane()
  {
    ConcentrationModel c = new ConcentrationModel();
    GridPane grid = new GridPane();

    ColumnConstraints col1 = new ColumnConstraints();
    col1.setPercentWidth( 50 );

    grid.getColumnConstraints().addAll(col1, col1, col1, col1);
    RowConstraints row1 = new RowConstraints();
    row1.setPercentHeight( 50 );
    grid.getRowConstraints().addAll(row1, row1, row1, row1);


    for(int row = 0; row < 4; row ++){
        for(int col = 0; col < 4; col++){
            Button btn = new Button();
            ImageView image = new ImageView(c.getCards().get(0).getImage());
            image.setFitWidth(WIDTH/4);
            image.setFitHeight(HEIGHT/4);
            btn.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
            btn.setGraphic(image);
            btn.addActionListener(this);
            grid.add(btn, col, row);


        }
    }
    return grid;
  }


  public void actionPerformed(ActionEvent e) 
  {
    moves++;
  }  

}

【讨论】:

  • 这是一个 JavaFX 问题。
  • 我知道。我只想指出,父类可以实现一个Listener接口。作者也没有包含太多细节。
猜你喜欢
  • 2011-08-21
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-21
  • 2015-02-04
  • 2023-03-24
相关资源
最近更新 更多