【问题标题】:JavaFX FXML access succeed with lookup() method but not with @FXML annotationJavaFX FXML 访问使用lookup() 方法成功,但没有@FXML 注释
【发布时间】:2016-06-12 16:47:02
【问题描述】:

我开始探索 JavaFX FXML 应用技术。

我使用在 Main 类中访问的一个主 Stage,带有 Main.getStage(),它在应用程序启动时使用覆盖方法 public void start(Stage stage) 调用。里面有两个public static Scene,在切换它们时保持持久性。

@Override
public void start(Stage stage) throws Exception {
    STAGE = stage;
    LOGIN = new Scene(FXMLLoader.load(getClass().getResource("Login.fxml")));
    REGISTER = new Scene(FXMLLoader.load(getClass().getResource("Register.fxml")));

    STAGE.setScene(LOGIN);
    STAGE.setTitle("FXApplication");
    STAGE.show();
}

public static Stage getStage() {
    return STAGE;
}

两个场景都有相同的控制器类MainController。使用:

  • 带有fx:id="buttonLoginRegister"的按钮可以转到REGISTER场景
  • 带有fx:id="buttonRegisterBack" 的按钮可返回LOGIN 之一。

两者都具有相同的onClick 事件handleButtonAction(ActionEvent event)。 TextFields 是用户名登录/注册的字段。

@FXML private Button buttonLoginRegister;
@FXML private Button buttonRegisterBack;
@FXML private TextField fieldLoginUsername;
@FXML private TextField fieldRegisterUsername;

@FXML
private void handleButtonAction(ActionEvent event) throws IOException {

    Stage stage = Main.getStage();

    if (event.getSource() == buttonLoginRegister) {     
        stage.setScene(Main.REGISTER);
        stage.show();

        // Setting the text, the working way
        TextField node = (TextField) stage.getScene().lookup("#fieldRegisterUsername");
        node.setText(fieldLoginUsername.getText());

        // Setting the text, the erroneous way
        // fieldRegisterUsername.setText(fieldLoginUsername.getText());

    } else {
        stage.setScene(Main.LOGIN);
        stage.show();
    }
}

我的目标是将LOGIN TextField 中的值复制到REGISTER 场景中的值。使用上面的代码效果很好。但是首先我尝试通过以下方式访问另一个场景中的元素:

fieldRegisterUsername.setText(fieldLoginUsername.getText());

这是错误的。确切地说,fieldRegisterUsernamenull

为什么使用lookup(String id) 方法找到了一些元素,而不是使用@FXML 注释?

【问题讨论】:

  • 通常不鼓励为不同的 FXML(视图)共享控制器。如果您只是从 JavaFX 开始,我会特别建议您不要这样做。看看this question
  • 这是有争议的,很多开发人员都使用这种方式,并且相同的数字是agianst。在 2 个小场景的情况下,我个人认为共享控制器没什么不好。我之前已经阅读过链接的问题,但是它与我的持久性需求相冲突。
  • 不确定我理解“需要持久性”是什么意思。请参阅我的答案以解释为什么 lookup 在您的情况下有效。请记住,除非您为 FXMLLoader 设置了控制器,否则对 load 的每次调用都会创建控制器类的新实例。
  • @James_D 我认为你是对的,JavaFX' Greg Brown“FXML 文档与其控制器之间的 1:1 关联是设计使然。”上下文,以回复 Adam Bien(afterburner.fx 家伙),他想要多个控制器用于 1 个 fxml 文件。尽管如此,它清楚地表明它是 1:1 的设计。因此,做其他任何事情都会导致问题和丑陋,这不足为奇。 (尽管在控制器中实现 Initializable 是可选的)。顺便说一句,感谢您对 JavaFX 相关问题的回答!

标签: java javafx fxml


【解决方案1】:

正如我在评论中提到的,在不同的视图之间共享一个控制器很少是一个好主意,我强烈建议您为每个视图制作一个单独的控制器。

至于您的问题本身 - 您有两个控制器类实例,每次调用 FXMLLoader.load 时都有一个实例。据推测,一个视图有fieldLoginUsername TextField,而另一个有fieldRegisterUsername
如果满足if语句的条件,则表示活动场景是登录场景,因此处理它的控制器是具有fieldLoginUsername的控制器,所以fieldRegisterUsername自然为空。

但是在if 子句中的第一行,您将活动场景更改为注册场景,所以当您调用scene#lookup 时,您指的是控制器是注册控制器的场景,即有fieldRegisterUsername

如果您在更改活动场景之前调用scene#lookup,您会发现它也会返回 null。

如果您必须为控制器使用相同的类,您可能希望确保您只有一个该类的实例。这将需要使用FXMLLoader#setController

【讨论】:

  • 感谢您的解释。如果在不同的扫描之间使用一个控制器是一个坏主意,你能告诉我使用两个独立的控制器达到相同效果的方法吗?我不知道轻松传递值。
  • Arjan 在原始问题的评论中链接了两个出色的答案。
猜你喜欢
  • 2015-04-06
  • 1970-01-01
  • 2017-04-27
  • 1970-01-01
  • 2015-05-29
  • 2016-08-20
  • 2013-07-22
  • 1970-01-01
相关资源
最近更新 更多