2

I have some JavaFX components declared in my fxml file.

The Frame

and how do I get the values of the fields (Username, Password) when the button is pressed? (To perform the login).

  Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
  stage.setTitle("Login");
  stage.setScene(new Scene(root,400,300));
  stage.show();

or is this the complete wrong way to do it?

My Questions:

  1. Is it a good idea to declare all fields in the fxml file?
  2. How do I get the objects to acces the Values?
  3. If its the complete wrong way, how can it be done? (I want to use scenebuilder)

EDIT : https://hastebin.com/qexipogoma.xml <- My FXML fie and my controller

A.Rashad
  • 1,066
  • 12
  • 26
John E.
  • 55
  • 1
  • 8
  • Please post your FXML file and your controller code. – James_D Aug 24 '17 at 14:41
  • 2
    You need to provide those items with an `fx:id` and the reference them in your controller with `@FXML private TextField *fx:id goes here*;` I suggest reading up on how to do that via some tutorials. – Hypnic Jerk Aug 24 '17 at 14:53
  • Please don't post links to code: post the code in the question. – James_D Aug 24 '17 at 14:58

3 Answers3

6
Scene scene = stage.getScene();
Button btn = (Button) scene.lookup("#myBtnID");
TextField txt = (TextField ) scene.lookup("#myTxtID");

you're looking for:

txt.getText();

and

btn.setOnAction( lambda here );

Documentation:

Button

TextField

EDIT: declare ids this way

<TextField fx:id="myTxtID" ...  />
  • Were is the the button id? I cant see one here : https://hastebin.com/qexipogoma.xml – John E. Aug 24 '17 at 14:53
  • well you should define it in you fxml... otherwise you can look through all your parent children and look for instances of TextField and guess which one is which... but normal people just assign IDs and directly look them up – Laurent Schwitter Aug 24 '17 at 14:55
  • This won't work. Lookups will return null unless CSS has been applied, which doesn't happen by default until the first layout pass occurs. Lookups are generally very fragile; the proper approach is to define a controller class and inject the fields into it. If you really want to hack it like this, get the namespace from the FXML loader and get the objects from the namespace after loading the FXML. – James_D Aug 24 '17 at 15:00
  • ofc it works... i agree and normally also use separate controllers but lookups do work... and creating a separate controller for ONE button seems excessive... – Laurent Schwitter Aug 24 '17 at 15:04
  • It only works if the scene has been rendered: nothing in the code you posted guarantees that. If you're going to access the controls in the place you load the FXML, why would you not use the FXML loader namespace, which always works, instead of a mechanism that relies on arbitrary timing of things you have no control over? – James_D Aug 24 '17 at 15:08
  • well if you're sure about this you just taught me something but I'm not 100% sure that's true.. to be honest I've been extending my custom scene/controller classes for so long I might have prevented what you're saying in some other way... – Laurent Schwitter Aug 24 '17 at 15:12
  • See, e.g. https://stackoverflow.com/questions/32773847/scene-lookup-returns-null-if-i-search-my-vbox – James_D Aug 24 '17 at 15:14
  • you seem to be right: https://stackoverflow.com/questions/36769899/javafx-node-lookup-returning-null-only-for-some-elements-in-parent-loaded-with – Laurent Schwitter Aug 24 '17 at 15:15
  • Thank you! This answer helped me. – excelsiorious May 24 '19 at 14:42
4

Is it a good idea to declare all fields in the fxml file?

This depends on what you need. In this case you do not need to add/remove any parts of the scene dynamically. You'll probably replace the window/scene on a successful login. There should not be any issue with creating this scene via fxml.

How do I get the objects to acces the values?

Use a controller with the fxml and access the values via this controller.

<AnchorPane fx:controller="mypackage.LoginController" ...>
   <children>
      ...
      <TextField fx:id="username" ... />
      ...
      <PasswordField fx:id="password" ... />
      ...
      <Button onAction="#login" ... />
   </children>
</AnchorPane>
package mypackage;

...

public class LoginController {

    private boolean login = false;

    @FXML
    private TextField username;

    @FXML
    private PasswordField password;

    @FXML
    private void login() {
        // regular close the login window
        login = true;
        password.getScene().getWindow().hide();
    }

    public String getUsername() {
        return username.getText();
    }

    public String getPassword() {
        return password.getText();
    }

    public boolean isLogin() {
        return login;
    }

    public void resetLogin() {
        // allow reuse of scene for invalid login data
        login = false;
    }

}
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Stage stage = new Stage(new Scene(loader.load()));
LoginController controller = loader.getController();

boolean loginSuccess = false;

stage.showAndWait();

if (controller.isLogin()) {
    if (checkLogin(controller.getUsername(), controller.getPassword())) {
        // handle login success
    } else {
        // handle invalid login
    }
}
fabian
  • 80,457
  • 12
  • 86
  • 114
1

Try using SceneBuilder. It will produce an FXML file and a compatible controller. This will give you a good start.

Jonathan Rosenne
  • 2,159
  • 17
  • 27