【问题标题】:How to manage multiple buttons with one event handler method in Javafx and Scene Builder如何在 Javafx 和 Scene Builder 中使用一种事件处理程序方法管理多个按钮
【发布时间】:2018-04-19 02:31:04
【问题描述】:

我有 14 对按钮与两组 textFields 相关联,它们将其关联的 textFields 递增和递减 2。每个文本字段显示要在杠铃上加载多少对特定重量的板。 它们存储在两个二维数组中,一个用于磅,另一个用于千克。 [递增或递减][按钮]

final Button[][] poundIncrementDecrementButton = new Button[2][7];
final Button[][] kilogramIncrementDecrementButton = new Button[2][7];

我正在使用 Scene Builder 和 JavaFX,并且试图避免编写 28 个 @FXML 事件处理程序。 到目前为止,这是我想出的遍历每个数组的方法,但我不确定如何替换 lambda 表达式以使其工作。

// assigns event handlers to increment and decrement buttons.
private void incrementDrecimentButtonEventHandlers() {

    // p=1 increment buttons, p=2 decrement buttons
    for (int p = 0; p < poundIncrementDecrementButton.length; p++) {
        // loops through buttons
        for (int j = 0; j < poundIncrementDecrementButton[p].length; j++) {
            Button incrementButton = poundIncrementDecrementButton[p][j];
            final int incrementDecriment = p;
            final int textField = j;
            incrementButton.setOnAction((ActionEvent event) -> {
                incrementDecrementPlate("pounds", incrementDecriment, textField);
            });
        }

        // k=1 increment buttons, k=2 decrement buttons
        for (int k = 0; k < kilogramIncrementDecrementButton.length; k++) {
            // loops through buttons
            for (int j = 0; j < kilogramIncrementDecrementButton[k].length; j++) {
                Button incrementButton = kilogramIncrementDecrementButton[k][j];
                final int incrementDecriment = k;
                final int textField = j;
                incrementButton.setOnAction((ActionEvent event) -> {
                    incrementDecrementPlate("kilograms", incrementDecriment, textField);
                });
            }

        }
    }
}

然后我让事件处理程序使用相关索引调用此方法。

// increments or decrements the plates
private void incrementDecrementPlate(String unit, int incrementDecrement, int textField) {

    Double oldValue = Double.parseDouble(poundTextFieldList.get(textField).getText());
    String incremented;
    String decremented;

    if (oldValue % 2 != 0) {
        incremented = Double.toString(oldValue + 1);
    } else {
        incremented = Double.toString(oldValue + 2);
    }

    if (oldValue % 2 != 0) {
        decremented = Double.toString(oldValue - 1);
    } else if (oldValue != 0) {
        decremented = Double.toString(oldValue - 2);
    } else {
        decremented = Double.toString(oldValue);
    }

    switch (unit) {
        case "pounds":
            if (incrementDecrement == 0) {
                poundTextFieldList.get(textField).setText(incremented);
            } else {
                poundTextFieldList.get(textField).setText(decremented);
            }
            break;
        case "kilograms":
            if (incrementDecrement == 0) {
                kilogramTextFieldList.get(textField).setText(incremented);
            } else {
                kilogramTextFieldList.get(textField).setText(decremented);
            }
            break;
    }
}

【问题讨论】:

  • 这似乎需要很多代码来做一些可以用更少的代码编写的事情。
  • 似乎完全用 Java 来完成 UI 布局和事件处理的这一部分要容易得多 - 与拥有 FXML 相比,您已经发布的代码只需要很少的额外代码包含 28 个(或 56 个?)&lt;Button&gt; 元素和 14 个文本字段元素的文件...
  • 看来您是手动进行的,这是可能的,但从长远来看,JavaFX 方法是最好的。在代码中创建 UI 控件,使用 Controller,Buttons 设置属性,TextFields 观察属性。基本知识 - 查看 Oracle JavaFX 教程
  • @Siraj 这正是我正在做的。所有这些代码都位于我的控制器类中。我使用 Scene Builder 来设计 UI。我正在尝试尽可能地坚持 MVC。

标签: java javafx fxml scenebuilder actionevent


【解决方案1】:

经过一些实验,我想出了一个解决方案。请记住,这是我使用 Scene Builder、FXML 和 JavaFX 坚持使用 MVC 架构的尝试。

有 14 种不同的盘子,7 磅和 7 公斤。每个盘子都有一个文本字段,用于显示给定重量的杠铃需要装载多少个。这些文本字段存储在 ObservableLists 中,并在控制器的其他地方提供侦听器。

// textFields associated with 45, 35, 25, 15, 10, 5, 2.5lb plates
ObservableList<TextField> poundTextFieldList = FXCollections.observableArrayList();
// textFields associated with 25, 20, 15, 10, 5, 2.5, 1.25kg plates
ObservableList<TextField> kilogramTextFieldList = FXCollections.observableArrayList();

这些数组存储车牌的数量。

int[] poundPlatesToLoad = calculator.getPoundPlatesToLoad();
int[] kilogramPlatesToLoad = calculator.getKilogramPlatesToLoad();

这些 ArrayList 存储增量按钮

private final ArrayList<Button> poundIncrementButtons = new ArrayList();
private final ArrayList<Button> poundDecrementButtons = new ArrayList();
private final ArrayList<Button> kilogramIncrementButtons = new ArrayList();
private final ArrayList<Button> kilogramDecrementButtons = new ArrayList();

由于我使用 Scene Builder 来设计 GUI,每个按钮都需要 @FXML 标签来识别它们。我认为没有办法解决这个问题,所以控制器中有 28 个。

@FXML
private Button poundIncrement45Button;
@FXML
private Button poundDecrement45Button;

然后,为了避免编写 28 个处理程序,我编写了与每个 ArrayList 关联的 4 个处理程序。

public void poundIncrementButtonPressed(ActionEvent event) {
    System.out.println("pound increment button pressed");
    Button button = (Button) event.getSource();
    // identifies which plate is to be incremented
    int plate = poundIncrementButtons.indexOf(button);
    incrementDecrementPlate(0, 0, plate);
}

还有一种增加或减少正确文本字段的方法。

private void incrementDecrementPlate(int unit, int incrementDecrement, int textField) {

    int oldValue;
    if(unit == 0){
        oldValue = (int) poundPlatesToLoad[textField];
    } else {
        oldValue = (int) kilogramPlatesToLoad[textField];
    }

    String incremented;
    String decremented;

    if (oldValue % 2 != 0) {
        incremented = Integer.toString(oldValue + 1);
    } else {
        incremented = Integer.toString(oldValue + 2);
    }

    if (oldValue % 2 != 0) {
        decremented = Integer.toString(oldValue - 1);
    } else if (oldValue != 0) {
        decremented = Integer.toString(oldValue - 2);
    } else {
        decremented = Integer.toString(oldValue);
    }

    switch (unit) {
        case 0:
            if (incrementDecrement == 0) {
                poundTextFieldList.get(textField).setText(incremented);
            } else {
                poundTextFieldList.get(textField).setText(decremented);
            }
            break;
        case 1:
            if (incrementDecrement == 0) {
                kilogramTextFieldList.get(textField).setText(incremented);
            } else {
                kilogramTextFieldList.get(textField).setText(decremented);
            }
            break;
    }
}

这是到目前为止的程序图像。每个文本字段都会动态响应更改。右侧的杠铃显示千克板以响应文本字段的变化。

【讨论】:

  • SceneBuilder 只是一个创建 FXML 文件的工具,类似于编写 HTML 或使用可视化编辑器。您可以在其中设置控制器,以便它会自动为您添加 @FXML 字段。顺便说一句,您的新代码可以压缩,但只要它有效......
  • Scene Builder 写入 FXML 文件,但据我了解,为了将 FXML 文件中的元素链接到控制器类,您需要在控制器类中使用 @FXML 标签才能工作以编程方式使用它们(按钮、文本字段)。是的,我同意,我会努力压缩它。
  • 我也知道 Scene Builder 可以生成一个骨架控制器类,但它只为按钮生成 28 个单独的处理程序,这正是我试图避免的。
【解决方案2】:

以下代码演示了如何让一组 (2) 个按钮增加文本字段的值:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class FxMain extends Application {

    private Button[] increment, decrement;
    private TextField[] txt;
    private static final int numberOfGroups = 3;

    @Override
    public void start(Stage stage) {

        initComponents(numberOfGroups);
        GridPane root = new GridPane();
        for(int row =0; row < numberOfGroups; row++){ //add all components 
            root.addRow(row, decrement[row], txt[row],increment[row]);
        }
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    //create and initialize components 
    private void initComponents(int size) {
        increment = new Button[size]; decrement = new Button[size];
        txt = new TextField[size];

        for(int group = 0; group < size; group++) {
            final int i = group;
            txt[i] = new TextField(String.valueOf(0));
            increment[i] = new Button("+");
            increment[i].setOnAction(a-> updateTxtField(txt[i], 1));//assign handle 
            decrement[i] = new Button("-");
            decrement[i].setOnAction(a-> updateTxtField(txt[i],-1));
        }
    }
    //increment text filed value
    private void updateTxtField(TextField textField, int i) {

        int newValue = Integer.valueOf(textField.getText()) + i;
        textField.setText(String.valueOf(newValue));
    }

    public static void main(String[] args) { launch(args);}
}

如有需要,请随时要求澄清。 如需更多帮助,请发帖MCVE

【讨论】:

  • 感谢您的回复。由于我使用 Scene Builder 创建 GUI,我不确定如何在控制器类中没有 @FXML 标记的情况下将事件处理程序正确链接到按钮?
  • 如需更多帮助,请发帖minimal reproducible example
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 2015-04-01
  • 1970-01-01
相关资源
最近更新 更多