【问题标题】:How to ensure Fxml method on button will be called before listener on it?如何确保在监听按钮之前调用按钮上的 Fxml 方法?
【发布时间】:2018-07-27 16:05:47
【问题描述】:

我有一个controller,它会启动一个名为file 的新窗口:

// MainController.java
Stage primaryStage = new Stage();
FXMLLoader fx = new FXMLLoader(Paths.get("../file.fxml").toUri().toURL());
Scene scene = new Scene(fx.load());
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.centerOnScreen();

FileController control = (FileController ) fx.getController();
control.getValiderBE().setOnAction(event1 -> {
   System.out.prinln("here 1");
});

我在FXML file 中有一个按钮:

// file.fxml, fx:controller="FileController"
<Button fx:id="validerBE" onMouseClicked="#validerClickBE" text="Valider">
</Button>

在其controllerFileController 的实例)中我得到了:

FileController.java
@FXML
private Button validerBE;
@FXML
void validerClickBE(MouseEvent event) {
   System.out.prinln("here 2");
}
public Button getValiderBE() {
    return validerBE;
}

按以下顺序打印:here 1 => here 2FileController 中的 sometines 方法甚至没有被调用^^ 就像here 1 调用中的事件关闭

但我会按其他顺序,因为新的window 将一个元素添加到列表中,第一个源controller 应该刷新TableView(所以在添加操作之后)

【问题讨论】:

  • 如果你想执行两个活动,你应该对两者使用相同的操作,为什么你不能使用相同的?
  • 因为它们不在同一个控制器中
  • 无论如何,将 UI 控件暴露在控制器之外是非常糟糕的做法。为什么你需要(或认为你需要)这样做?一般来说(尽管有一些 hacky 变通方法),没有办法控制监听器的执行顺序,所以如果两个动作相关或相互依赖,它们应该在同一个处理程序中执行
  • 另外:不要使用onMouseClicked作为按钮;使用onAction,否则如果用户使用键盘,处理程序将不会被调用。
  • @James_D 我“必须”这样做,因为我需要刷新 TableView 并且因为数据存储在其他地方并且需要修改(创建关联的 objectPropety)我只找到了清除的方法并再次设置项,只能在主控制器中完成

标签: java events button javafx javafx-8


【解决方案1】:

首先,请注意您应该使用onAction 来处理按钮点击,而不是onMouseClicked。这样做的原因是,如果用户导航到按钮并激活它(通常使用空格键),或者在没有鼠标的情况下触发按钮(例如使用助记符),onMouseClicked 处理程序将不会被调用。

所以你应该有

<Button fx:id="validerBE" onAction="#validerClickBE" text="Valider" />

@FXML
void validerClickBE(ActionEvent event) {
   System.out.prinln("here 2");
}

对于事件的排序:没有通用的方法来控制调用事件处理程序的顺序。有一些特殊情况,您可以在某些特定情况下利用它们,但通常不指定处理程序调用的顺序。因此,如果您有两个相互依赖的操作,它们应该在同一个处理程序中执行。

无论如何,将 UI 控件暴露在控制器之外通常是不好的做法 - 它违反了封装原则,并且会使您的代码更难维护。通常,您应该将数据模型传递给控制器​​,然后控制器可以调用它需要调用的数据模型上的任何操作。

至少,您可以定义一个字段来表示按下按钮时要执行的操作,并从您现有的处理程序中调用它,尽管当然更可取的是适当的 MVC 方法:

public class FileController {

    private Runnable onValidate = () -> {} ;

    public void setOnValidate(Runnable onValidate) {
        this.onValidate = onValidate ;
    }

    @FXML
    private void validerClickBE(ActionEvent event) {
        // whichever order you need....
        onValidate.run();
        System.out.println("here 2");
    }
}

当然还有

FXMLLoader fx = new FXMLLoader(Paths.get("../file.fxml").toUri().toURL());
Scene scene = new Scene(fx.load());
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.centerOnScreen();

FileController control = (FileController ) fx.getController();
control.setOnValidate(() -> System.out.println("here 1"));

【讨论】:

  • 谢谢,我在模型中更改了好的属性,一切正常
猜你喜欢
  • 1970-01-01
  • 2016-12-31
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
  • 2021-02-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多