1
votes

I had some problems in a project with KeyEvent. A combo box that switch values from one to another when key Enter is pressed.

After some attempts the problem showed was that the Enter key generates 2 times the event, so the combo box apparently didn't change.

Then, I tried to make a simple test project with this snippet:

            window.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent event) {
            if(event.getCode().equals(KeyCode.ENTER))
                System.out.println("print");
        }
    });

The program prints twice every enter. Is it possible that KeyCode.ENTER refers to more than one key or something like this? If i change KeyCode.ENTER in something else (tried with SPACE or some letters) it works properly. Is possible to do something to solve this issue?

I made a simple project with 3 files :

Main

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;


public class Main extends Application {
    private static Stage window;

    @Override
    public void start(Stage primaryStage) throws Exception{
        window = primaryStage;

        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();
    }


    public static Stage getWindow(){return window;}

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

Controller:

import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;

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


public class Controller implements Initializable {

    @FXML
    TextField textField;

    Stage window;


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        window = Main.getWindow();
        window.addEventFilter(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event) {
                if (event.getCode().equals(KeyCode.ENTER))
                    System.out.println("print");
            }
        });
    }
}

Sample :

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity"
            minHeight="-Infinity" minWidth="-Infinity"
            prefHeight="400.0" prefWidth="600.0"
            fx:controller="Controller"
            xmlns="http://javafx.com/javafx/8.0.121"
            xmlns:fx="http://javafx.com/fxml/1">
    <children>
        <TextField fx:id="textField" layoutX="14.0" layoutY="14.0" />
    </children>
</AnchorPane>

It prints twice when Enter is pressed. Before the insertion of the TextField instead worked as expected.

2
Works entirely as expected for me. Post a minimal reproducible example.James_D
I don't know if could be helpful but I am using IntelliJ on a Sierra OS Tried also with a Windows 10 (IntelliJ IDE)Stefano Miceli
No, that's not helpful at all.James_D
I don't know why but if I unfocus the textfield it works properly. So the double trigger is when the TextField is focused. Thanks for the helpStefano Miceli

2 Answers

1
votes

Change this line

window.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {

to

window.addEventFilter(KeyEvent.KEY_RELEASED, new EventHandler<KeyEvent>() {

Edit code for @James_D

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;

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


public class Controller implements Initializable {

    @FXML
    TextField textField;

    Stage window;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        window = Main.getWindow();
        window.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
            System.out.println("Key Code:"+event.getCode()+" Target:"+event.getTarget());
        });
//        textField.setOnAction(event -> {});
    }
}

When this runs you get the output of

Key Code:ENTER Target:TextField[id=textField, styleClass=text-input text-field]
Key Code:ENTER Target:AnchorPane@7a78d90b[styleClass=root]

If you uncomment the textField Line the output is

Key Code:ENTER Target:TextField[id=textField, styleClass=text-input text-field]

@James_D Initially I did not but after some looking around and I think it has to do with the preset setOnAction command the description is "The action handler associated with this text field, or null if no action handler is assigned. The action handler is normally called when the user types the ENTER key." So when you change the .setOnAction to consume or nothing it prevents this error which I think is because it is no longer kicking out the enter command to the anchorPane surrounding. Now as to why the KeyEvent.KEY_RELEASED works I think this is because the enter Key can only be released once per press down as opposed to the press which can send the command multiple times. This is all complete speculation because I have no proof of what I'm talking about if you can figure out a more reasonable explanation why I would love to know. This was supposed to be a comment but got to long.

2
votes

I had the same issue. Every key would trigger the EventFilter once, except ENTER, which would trigger it twice.

A more simple and elegant solution was to simply add e.consume() into your block that respons to enter into the EventFilter.

if(e.getCode().toString().equals("ENTER")){
    e.consume();
}