Nate Simpson
Nate Simpson

Reputation: 118

TextField requestFocus losing first keypress? (JavaFX2)

I have a TextField embedded in an AnchorPane along with a couple of buttons. The TextField does not have focus by default, because I want it to show the prompt text (see prompttext in textfield of javafx 2 hides on focus after some java 7 update - this appears to be a known issue). I want the TextField to receive focus when the user presses any key other than ENTER or ESCAPE. I've created an EventHandler that is attached to my AnchorPane.setOnKeyPressed() (and to the buttons' onKeyPressed listeners) which runs a switch on the keyboard event and defaults to:

                    default:
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            myTxt.requestFocus();
                            myTxt.fireEvent(event);
                        }
                    });

This does send the focus to the TextField; however, the key that I've pressed does not actually show up in the TextField. In other words, if I type

test

the TextField will receive the focus, but only

est

shows up in the field. I've added logging to my KeyEvent listener for both the anchorpane/buttons and to the TextField, which shows me:

Oct 29, 2013 2:22:11 PM com.myapp.AppMainController$4 handle
INFO: Got key t at source Button[id=myBtn, styleClass=button]
Oct 29, 2013 2:22:11 PM com.myapp.AppMainController$6 handle
INFO: Got key t at source TextField[id=myTxt, styleClass=text-input text-field]

So the key event is getting to the TextField, however, it never shows up in the box. If I continue to type, the remaining text does show up, and if I gain focus by typing a combination like SHIFT-T for a capital T, it will show up (it seems that the shift keypress is the one that is "lost" instead of the letter itself).

Has anyone else encountered this? Is this a bug in JavaFX2 or am I doing something wrong? I'm using Java 7u45 with its included JavaFX 2.2.45, for reference.

Edit 1: I should clarify that this happens on switching focus to the TextField regardless of whether the focus was switched from the pane or a button.

Edit 2 (Solution): The actual problem was the "Platform.runLater" wrapper. If I simply request focus without the "runLater", my key events show up as I expect.

                    default:
                        myTxt.requestFocus();

Upvotes: 1

Views: 1736

Answers (1)

thatsIch
thatsIch

Reputation: 848

I am not sure how your context looks like but I solved it like this

public class Main extends Application {
    @Override
    public void start(Stage stage) {        
        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));

        final TextField textField = new TextField();
        final Button button = new Button();

        vbox.getChildren().addAll(textField, button);


        vbox.onKeyPressedProperty().set(new EventHandler<KeyEvent>() {
            @Override public void handle(KeyEvent event) {
                textField.requestFocus();
            }
        });

        stage.setScene(new Scene(vbox, 300, 500));
        stage.show();
    }

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

the important part would be

vbox.onKeyPressedProperty().set(new EventHandler<KeyEvent>() {
    @Override public void handle(KeyEvent event) {
        textField.requestFocus();
    }
});

By using the keyPressedProperty, it will already activate when you press the any button and not when you type/release it. Works with capitals and non-capitals.

Edit

The button is inserted to be able to "test" non-focus of the TextField by clicking it you can give it the focus.

Edit 2

to match the actual answer, you use some workaround using Platform.runLater which you actually need in multiple cases. This is a code inside an IntegerField (extends TextField) so I am its own methods.

this.setOnMouseClicked(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent paramT) {
        Platform.runLater(new Runnable() {
            @Override public void run() {
                if (isFocused() && !getText().isEmpty()) {
                    selectAll();
                }               
            }
        });
    }
});

Upvotes: 1

Related Questions