JavaFx:处理大量按钮的最佳实践是什么

JavaFx:处理大量按钮的最佳实践是什么,java,javafx,Java,Javafx,我正在使用JavaFx编写一个项目,它是一个3D Tic Tac Toe,我有一个3D 4*4*4页面,我用scene builder 2.0设计了这个页面,并放置了许多按钮作为控件,所以当你点击一个按钮时,它的文本会变成“R”,当计算机选择它的移动时,它会变成“B”,总之,这是我的控制器类的一个示例: public class Controller { @FXML private Button b131; @FXML private Button b111; @FXML private B

我正在使用JavaFx编写一个项目,它是一个3D Tic Tac Toe,我有一个3D 4*4*4页面,我用scene builder 2.0设计了这个页面,并放置了许多按钮作为控件,所以当你点击一个按钮时,它的文本会变成“R”,当计算机选择它的移动时,它会变成“B”,总之,这是我的控制器类的一个示例:

public class Controller {
@FXML
private Button b131;

@FXML
private Button b111;

@FXML
private Button b133;

@FXML
private Button b232;

@FXML
private Button b331;

@FXML
private Button b132;

@FXML
private Button b231;

@FXML
private Button b314;

@FXML
private Button b113;

@FXML
private Button b234;

@FXML
private Button b212;

@FXML
private Button b333;

@FXML
private Button b311;
...
 @FXML
public void Initialize() {
    assert b131 != null : "fx:id=\"b131\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b111 != null : "fx:id=\"b111\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b133 != null : "fx:id=\"b133\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b232 != null : "fx:id=\"b232\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b331 != null : "fx:id=\"b331\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b132 != null : "fx:id=\"b132\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b231 != null : "fx:id=\"b231\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b314 != null : "fx:id=\"b314\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b113 != null : "fx:id=\"b113\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b234 != null : "fx:id=\"b234\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b212 != null : "fx:id=\"b212\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b333 != null : "fx:id=\"b333\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b311 != null : "fx:id=\"b311\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b112 != null : "fx:id=\"b112\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b134 != null : "fx:id=\"b134\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b233 != null : "fx:id=\"b233\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b211 != null : "fx:id=\"b211\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b332 != null : "fx:id=\"b332\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b214 != null : "fx:id=\"b214\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b313 != null : "fx:id=\"b313\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b114 != null : "fx:id=\"b114\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b213 != null : "fx:id=\"b213\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b334 != null : "fx:id=\"b334\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b312 != null : "fx:id=\"b312\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b142 != null : "fx:id=\"b142\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b241 != null : "fx:id=\"b241\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b141 != null : "fx:id=\"b141\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b122 != null : "fx:id=\"b122\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b144 != null : "fx:id=\"b144\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b243 != null : "fx:id=\"b243\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b221 != null : "fx:id=\"b221\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b342 != null : "fx:id=\"b342\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b121 != null : "fx:id=\"b121\" was not injected: check your FXML file 'Scene.fxml'.";
    assert b143 != null : "fx:id=\"b143\" was not injected: check your FXML file 'Scene.fxml'.";
...
我已经设置了我的按钮fx:id在这个逻辑中,'b'代表按钮,第一个整数代表它的页面,第二个和第三个整数代表该按钮的行和列,现在我的问题是事件处理,我已经编写了一个函数,它可以这样做,并通过scene builder的代码部分连接到我的按钮,它可以工作:

public void ButtonHandler(){
b111.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
    @Override
    public void handle(javafx.event.ActionEvent event) {
        b111.setText("R");
    }
});
...
public void ButtonHandler(){
b111.setOnAction(新的EventHandler(){
@凌驾
公共无效句柄(javafx.event.ActionEvent){
b111.setText(“R”);
}
});
...
但我希望按钮名称是一种动态的,但我不知道如何有效地做到这一点。
任何帮助都将不胜感激。

我想我通常建议不要在FXML中创建类似的按钮,而是在控制器代码的循环中创建它们。因此,您的FXML文件可以定义布局:


然后,控制器可以使用明显的
for
循环简洁地定义按钮:

package tictactoe3d;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;

public class GameController {

    @FXML
    private GridPane page0 ;
    @FXML
    private GridPane page1 ;
    @FXML
    private GridPane page2 ;
    @FXML
    private GridPane page3 ;

    public void initialize() {
        GridPane[] pages = {page0, page1, page2, page3};

        for (int page = 0; page < 4; page++) {
            for (int row = 0; row < 4; row ++) {
                for (int col = 0; col < 4; col++) {
                    Button button = new Button("O");
                    pages[page].add(button, col, row);

                    String message = "Button pressed on page "+page+" row "+row+" column "+col;
                    button.setOnAction(e -> {
                        button.setText("R");
                        // replace with real data update:
                        System.out.println(message);
                    });
                }
            }
        }
    }
}

您甚至可以更进一步,定义一个带有四个按钮的“行”FXML,并使页面包含它的四个副本(而不是16个按钮)但是,这将阻止您使用
GridPane
;您必须使用包含
HBox
es的
VBox
,这可能会使您很难将所有内容都保存在网格中。

我想我通常建议不要在FXML中创建类似的按钮,而是在控制器代码中的循环中创建它们。因此,您的FXML文件可以定义布局:


然后,控制器可以使用明显的
for
循环简洁地定义按钮:

package tictactoe3d;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;

public class GameController {

    @FXML
    private GridPane page0 ;
    @FXML
    private GridPane page1 ;
    @FXML
    private GridPane page2 ;
    @FXML
    private GridPane page3 ;

    public void initialize() {
        GridPane[] pages = {page0, page1, page2, page3};

        for (int page = 0; page < 4; page++) {
            for (int row = 0; row < 4; row ++) {
                for (int col = 0; col < 4; col++) {
                    Button button = new Button("O");
                    pages[page].add(button, col, row);

                    String message = "Button pressed on page "+page+" row "+row+" column "+col;
                    button.setOnAction(e -> {
                        button.setText("R");
                        // replace with real data update:
                        System.out.println(message);
                    });
                }
            }
        }
    }
}

您甚至可以更进一步,定义一个带有四个按钮的“行”FXML,并使页面包含它的四个副本(而不是16个按钮)。这将阻止您使用
GridPane
;您必须使用包含
HBox
es的
VBox
,这可能会使您很难将所有内容都保存在网格中。

也许最好不要在FXML中创建这些按钮。在FXML中创建用于保存按钮的窗格和其他控件,然后创建并添加按钮在Java代码中。这样你可以使用循环和数组等。@fabian链接答案的可能重复非常好:使用64个按钮可能会延长你的理智。创建一个窗格,按所需次数迭代循环,然后创建一次按钮。我会减少LOC,这也是最佳做法。也许最好不要这样做o在FXML中创建这些按钮。在FXML中创建用于保存按钮的窗格和其他控件,然后在Java代码中创建和添加按钮。这样,您可以使用循环和数组等。@fabian链接答案的可能重复非常好:使用64个按钮可能会让您的理智有所放松。创建一个窗格并迭代循环r所需的次数并创建一次按钮。我将减少LOC,这也是最佳做法。对于
for
循环中声明的这些按钮,我如何访问它们并处理我提到的另一个事件,即放置“B”在不丢失当前按钮的情况下被对手使用?我尝试在for循环外部声明按钮,并在内部声明新按钮,以便通过整个方法访问,但随后我丢失了该按钮的坐标,函数无法将按钮的文本设置为所需字符串,你知道吗?我没有真正理解您所要求的;当您在循环中创建按钮时,您可能只需要注册您需要的其他处理程序。但是,如果您以后确实需要访问所有按钮,只需创建一个数组,即
Button[][][]allButtons=newbutton[4][4][4];
并将您创建的按钮放入数组中:
allButtons[page][row][col 2]=button;
。那么我可以在最内部循环之外处理我的任何按钮,或者将单击的按钮发送到另一个联机方法吗?要在循环之外引用它们(可能在循环的最后一次迭代中创建的按钮除外),需要将它们存储在数组中。我不理解最后一部分…你是说
button.setOnAction(e->somethod(button));
可能,这(显然)是可能的。如果您想要方法中按钮在网格中的位置,那么您也应该传递它,即
button.setOnAction(e->somethod(button,page,row,col))
。对于
for
循环中声明的这些按钮,我如何能够访问它们并处理我提到的另一个事件,即放置“B”在不丢失当前按钮的情况下被对手使用?我尝试在for循环外部声明按钮,并在内部声明新按钮,以便通过整个方法访问,但随后我丢失了该按钮的坐标,函数无法将按钮的文本设置为所需字符串,你知道吗?我没有真正理解您所要求的;当您在循环中创建按钮时,您可能只需要注册您需要的其他处理程序。但是,如果您以后确实需要访问所有按钮,只需创建一个数组,即
Button[][][]allButtons=newbutton[4][4][4];
并将您创建的按钮放入数组中:
allButtons[page][row][col 2]=按钮;
。我能处理任何
package tictactoe3d;

import javafx.fxml.FXML;

public class GameController {
    @FXML
    private PageController page0Controller ;
    @FXML
    private PageController page1Controller ;
    @FXML
    private PageController page2Controller ;
    @FXML
    private PageController page3Controller ;

    public void initialize() {
        page0Controller.setPage(0);
        page1Controller.setPage(1);
        page2Controller.setPage(2);
        page3Controller.setPage(3);
    }
}