Search code examples
javafxfxml

How to request focus for a certain field?


I am developing a Login Dialog for a Smart Card Token Management with Certificate System. Below, I added example code to demonstrate the issue. If I start the application I first see a login dialog where I can enter a password for a user root. The first dialog still allows to navigate from one field to another field using tab key. But if I click the button ‘Ok’ then the focus is still on the ‘Ok’ button. Any ideas how to solve it? The focus needs to be on the first password field.

Package Java Source Folder

package loginregister.demologin;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class LoginRegisterApp extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(LoginRegisterApp.class.getResource("LoginRegisterDialog.fxml"));
        Scene scene = new Scene(fxmlLoader.load());
        stage.setTitle("Login Register Dialog");
        stage.setScene(scene);
        stage.show();
    }

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

package loginregister.demologin;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.stage.Stage;

import java.net.URL;
import java.util.ResourceBundle;

public class LoginRegisterController implements Initializable {
    public TextField tokenName;
    public PasswordField newPin;
    @FXML
    private Button btnLogin;
    private Stage primaryStage;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        this.primaryStage = new Stage();
    }

    @FXML
    void handleCancel(ActionEvent event) {
        Node node = (Node) event.getSource();
        this.primaryStage = (Stage) node.getScene().getWindow();
        this.primaryStage.hide();
    }

    public void switchForm(ActionEvent event) {
          tokenName.setText("admin1");
    }
}

Package loginregister.demologin in resource folder

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<StackPane xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="200.0" style="-fx-background-color: white;" fx:controller="loginregister.demologin.LoginRegisterController">
   <children>
      <VBox fx:id="hasAllPanes" alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="200.0">
         <children>
            <AnchorPane fx:id="outerAnchorPane" prefHeight="300.0" prefWidth="200.0" VBox.vgrow="ALWAYS">
               <children>
                  <AnchorPane fx:id="loginForm" layoutX="2.0" layoutY="64.0" prefHeight="150.0" prefWidth="200.0">
                     <children>
                        <TextField fx:id="tokenName" disable="true" editable="false" layoutX="14.0" layoutY="14.0" prefHeight="33.0" prefWidth="180.0" promptText="root" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" />
                        <PasswordField fx:id="newPin" layoutX="10.0" layoutY="61.0" prefHeight="33.0" prefWidth="180.0" promptText="Enter New PIN" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" />
                        <PasswordField layoutX="9.0" layoutY="110.0" prefHeight="33.0" prefWidth="180.0" promptText="Re-enter New PIN" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" />
                     </children>
                  </AnchorPane>
                  <HBox fx:id="hBoxOkCancel" alignment="CENTER" layoutX="10.0" layoutY="255.0" prefHeight="33.0" prefWidth="180.0" AnchorPane.bottomAnchor="11.913288912176938" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0">
                     <children>
                        <Button fx:id="btnLogin" graphicTextGap="10.0" mnemonicParsing="false" onAction="#switchForm" prefHeight="33.0" prefWidth="80.0" text="OK" HBox.hgrow="ALWAYS">
                           <font>
                              <Font size="12.0" />
                           </font>
                        </Button>
                        <Region prefHeight="33.0" prefWidth="30.0" HBox.hgrow="ALWAYS" />
                        <Button fx:id="btnCancel" graphicTextGap="10.0" mnemonicParsing="false" onAction="#handleCancel" prefHeight="33.0" prefWidth="80.0" text="Exit" HBox.hgrow="ALWAYS" />
                     </children>
                  </HBox>
               </children>
            </AnchorPane>
         </children>
      </VBox>
   </children>
</StackPane>

Solution

  • During the process of creating the question, I resolved the issue by myself. I added the line

    newPin.requestFocus();
    

    The method 'switchForm' needs to look like this:

    public void switchForm(ActionEvent event) {
            if (event.getSource() == btnLogin) {
                tokenName.setText("admin1");
                newPin.requestFocus();
            }
        }