I am trying to run a method in a controller class specified to a particular task, once a specified key is pressed using KeyListener. But i'm unable to detect the keypress and invoke the java.awt.event keyPressed
method. My code is as follows :
public class POSController implements KeyListener {
@Override
public void keyPressed(java.awt.event.KeyEvent e) {
if (e.getKeyCode() == com.sun.glass.events.KeyEvent.VK_F1) {
try {
paymentAction();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
What could have gone wrong? Thanks in advance.
Here is the minimal executable example of the problem.
public class POSController implements KeyListener {
@FXML
private TableView<Product> productTableView;
@FXML
private TableView<Item> listTableView;
@FXML
private MenuItem logoutItem, profile;
@FXML
private javafx.scene.image.ImageView backImage;
@FXML
private MenuButton menuButton;
@FXML
private TableColumn<Item, String> itemColumn;
@FXML
private ComboBox<String> clientId, paymentMethod;
@FXML
private TableColumn<Item, Double> priceColumn, totalColumn, discountPercentageColumn, amountColumn;
@FXML
private TableColumn<Item, Integer> quantityColumn;
@FXML
private TableColumn<Product, String> productColumn;
@FXML
private TextField searchField,discountPercentage,productField,priceField,quantityField,vatPercentage,subTotalField,discountField,totalVatField,vatField,netPayableField,totalDiscountField;
@FXML
private TextField ;
@FXML
private TextField ;
@FXML
private TextField ;
@FXML
private TextField ;
@FXML
private TextArea descriptionArea;
@FXML
private Button addButton, removeButton, paymentButton, resetTableButton, resetButton;
@FXML
private Label quantityLabel, errorLabel, userName, backLabel;
@FXML
private ObservableList<Item> ITEMLIST;
public static Scene paymentScene;
private double xOffset = 0;
private double yOffset = 0;
public static double finalNetPayablePrice = 0.0;
public static double finalSubTotalPrice = 0.0;
public static double finalVat = 0.0;
public static double finalDiscount = 0.0;
public static String clientName = null;
public static String selectedPaymentMethod = null;
public static List<String> itemNames = new ArrayList<>();
public static List<Double> itemDiscounts = new ArrayList<>();
public static List<String> prices = new ArrayList<>();
public static List<String> quantities = new ArrayList<>();
public static List<String> subTotals = new ArrayList<>();
public static ObservableList<Item> itemList;
public static List<String> columnItemData = new ArrayList<>();
public static List<String> columnQuantityData = new ArrayList<>();
@FXML
private void initialize() throws SQLException, ClassNotFoundException, IOException {
ObservableList<Product> productsData = ProductDAO.searchGoodProducts(app.values.getProperty("STATUS_TYPE1"));
populateProducts(productsData);
}
@FXML
private void populateProducts(ObservableList<Product> productData) throws ClassNotFoundException {
productTableView.setItems(productData);
}
@Override
public void keyTyped(java.awt.event.KeyEvent e) {
}
@Override
public void keyPressed(java.awt.event.KeyEvent e) {
if (e.getKeyCode() == java.awt.event.KeyEvent.VK_F1) {
try {
paymentAction();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
@Override
public void keyReleased(java.awt.event.KeyEvent e) {
}
@FXML
public void paymentAction() throws Exception {
if (validateInputsForPayment()) {
Payment payment = new Payment();
FXMLLoader loader = new FXMLLoader((getClass().getResource(app.values.getProperty("INVOICE_VIEW_LOCATION"))));
Parent root = loader.load();
Stage stage = new Stage();
root.setOnMousePressed((MouseEvent e) -> {
xOffset = e.getSceneX();
yOffset = e.getSceneY();
});
root.setOnMouseDragged((MouseEvent e) -> {
stage.setX(e.getScreenX() - xOffset);
stage.setY(e.getScreenY() - yOffset);
});
Scene scene = new Scene(root);
stage.initModality(Modality.APPLICATION_MODAL);
stage.initStyle(StageStyle.UNDECORATED);
stage.setScene(scene);
this.paymentScene = scene;
stage.showAndWait();
}
}
You shouldn't be using java.awt.event.KeyListener
for a JavaFX application. JavaFX has its own set of event API.
Assuming that POSController
is a controller class for a particular FXML:
public class POSController {
@FXML private BorderPane root; // Or any other Node from FXML file
@FXML private void initialize() {
javafx.event.EventHandler<javafx.scene.input.KeyEvent> handler = event -> {
if (event.getCode() == javafx.scene.input.KeyCode.F1) {
try {
paymentAction();
} catch (Exception e1) {
e1.printStackTrace();
}
}
};
// I'm using root to get scene, but any node would be fine
if (root.getScene() != null) {
root.getScene().addEventHandler(javafx.scene.input.KeyEvent.KEY_PRESSED, handler);
}
else {
root.sceneProperty().addListener((obs, oldScene, newScene) -> {
if (newScene != null) {
root.getScene().addEventHandler(javafx.scene.input.KeyEvent.KEY_PRESSED, handler);
}
});
}
}
}
This will add the key event to the Scene
. If you do not need to apply this event scene-wide, then you can add the event handler at other appropriate nodes.
If there are any input controls in the scene, then you may need to use setEventFilter()
instead of setEventHandler()
. This is because those controls are probably going to consume the key event during the event bubbling phase.