How can I detect the SPACE KeyEvent anywhere in my JavaFX app? - java

I want to detect a KeyEvent regardless of what element has focus in my JavaFX app - in particular, I want to detect the SPACE key. I tried to add a listener to the Scene that corresponds to my window:
scene.setOnKeyPressed(ev -> {
if (ev.getCode() == KeyCode.SPACE) {
System.out.println("GOOD");
}
});
But if I have a particular node with focus (like a ListView or Button) then it won't be detected.
How can I detect when the SPACE key is pressed regardless of whatever the user is doing in my app? I don't intend to interrupt whatever node is receiving the KeyEvent - I just want to know if it happens. One (ugly) solution would be adding the listener to all my nodes, but I would rather not if possible.

You can detect the KeyEvent by adding an event filter to the root node
Here is a quick example using some of the controls you mentioned:
#Override
public void start(Stage primaryStage) throws Exception{
TextField textfield = new TextField();
ListView listView = new ListView();
listView.getItems().add("One");
listView.getItems().add("Two");
listView.getItems().add("Three");
Button button = new Button("Button");
VBox root = new VBox(5, textfield, listView, button);
root.addEventFilter(KeyEvent.KEY_PRESSED, event->{
if (event.getCode() == KeyCode.SPACE) {
System.out.println("GOOD");
}
});
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
Note: On controls that generate a popup / overlay, a space might not be detected while it is showing, but will be detected when hidden yet still in focus. You can see this behaviour if you add a ComboBox or ColorPicker to the above example

Here is your code
scene.setOnKeyReleased(event ->{
if(event.getCode()== KeyCode.SPACE)
{
System.out.println("goog luck");
}
});

Related

How to make a JavaFX textfield not visible but still allow text to be entered into it

I have a javaFX application which takes input from a barcode scanner. The barcode scanner is recognised as a keyboard and always follows its input with a newline after any barcode is scanned (so onAction event is triggered).
At the moment I have a textfield which is always focused and linked to the barcode scanner, however I would like this to be hidden from the user. I tried using setVisible(False) but this seems to disable the textfield (onAction isn't triggered and textfield always empty)
I also tried putting the textfield off the screen which did work however because the screen has to be resizable I now have to use gridPane as the root so its not possible to do this anymore.
Just wondering if there is anyway to make the textfield invisible to the user but still allow it to be enabled?
You have a few possibilities to hide the text field using css. The easiest is to set the opacity to 0
TextField.css
.hidden{
-fx-opacity: 0;
}
Java
GridPane root = new GridPane();
// Add stylesheet
root.getStylesheets().add("TextField.css");
TextField textField = new TextField();
// Add class
textField.getStyleClass().add("hidden");
On the other hand I would really ask myself if this "hack" is the way to go. If your barcode scanner is simply inserting text, maybe the better solution is to add an event handler and handle the keystrokes accordingly:
EventHandler
root.addEventHandler(KeyEvent.ANY,(event)->{
System.out.println(event);
});
You do not actually need to have a TextField in the scene. In fact I wouldn't recommend doing that, since this would interfere with the focus and possibly the layout.
Instead I'd add a listener to the scene (or the root node of the scene making sure it or a descendant can get focus by setting the focusTraversable property to true, if necessary). You may need to use a event filter, if a node that consumes the KEY_PRESSED may have focus:
#Override
public void start(Stage primaryStage) throws IOException {
StackPane root = new StackPane(new Button());
Scene scene = new Scene(root);
final StringBuilder string = new StringBuilder();
scene.addEventFilter(KeyEvent.KEY_PRESSED, evt -> {
KeyCode code = evt.getCode();
if (code.isDigitKey()) {
// input part of the information
String name = code.toString();
string.append(name.charAt(name.length() - 1)); // make sure numpad keys do not
} else if (code == KeyCode.ENTER) {
// submit input
submitCode(string.toString());
string.setLength(0);
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
private void submitCode(String code) {
System.out.println(code);
}
Try using TextField.setText(java.lang.String).

Is it possible to get the 'new color' in JavaFx ColorPicker?

I'm trying to get the 'new color' value from a ColorPicker ('nouvelle couleur' in my image because it's french).
colorPicker.setOnAction((ActionEvent e) -> {
text.setFill(colorPicker.getValue());
});
When you set up a EventHandler for a ColorPicker, it only returns the value of the ColorPicker when you close it.
So I was wondering, is it possible to get this value ?
Sorry if there are any mistake, English is not my native language.
Yes, the valueProperty() from the ColorPicker control is updated every time you modify the selection in the dialog. Only if you cancel the change, it is backed out.
So you just need to add a listener to that property or bind it as required.
#Override
public void start(Stage primaryStage) {
ColorPicker picker = new ColorPicker(Color.ALICEBLUE);
Text text = new Text("Color Picker");
VBox root = new VBox(10, text, picker);
root.setAlignment(Pos.CENTER);
text.fillProperty().bind(picker.valueProperty());
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}

JAVAFX How to make a button stacked behind a Label clickable

How to make a button stacked behind a Label clickable?
Button
Button btn = new Button();
//TODO: button's main function, like onPressed, onReleased etc. here...
Custom label
CustomLabel sp = new CustomLabel("Some texts here"));
//TODO: custom label's main function, like a translucent background etc here...
//main purpose of this is to overlay the button
Main Pane
StackPane mainPane = new StackPane();
mainPane.getChildren.addAll(btn, sp);
With this, the area which the custom label overlays becomes unclickable.
Is there anyway to make the button still clickable even though overlay-ed, for example?
Or is there another way to do it? Something like setting label to not visible on click?
EDIT : To answer Itamar Green 's question..
By using the example as shown in this link: Mouse Events get Ignored on the Underlying Layer , it still does not seems to work. The button stacked under the layer is still not clickable.
sp.setPickOnBounds(false);
You can set the mouseTransparent property of the element(s) drawn on top to true. Note that this way all descendants of the node are ignored for mouse events:
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Say 'Hello World'");
btn.setOnAction((ActionEvent event) -> {
System.out.println("Hello World!");
});
Region region = new Region();
region.setStyle("-fx-background-color: #0000ff88;");
region.setMouseTransparent(true);
StackPane root = new StackPane(btn, region);
Scene scene = new Scene(root, 100, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
Comment out
region.setMouseTransparent(true);
and the button will no longer react to mouse events in any way...
thanks for your help. I think I have solved my own question.
All I did was set a clickable event for my label.
Label sp = new Label("some texts here")
sp.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
//copy over the button's event.
}
});
Not sure if there is any better way of doing this...
in addition with the correct answer. you can enable or disable " mouse transparent " property via fxml with scenebuilder

JavaFX virtual keyboard overlaps nodes

i have a question about using virtual keyboard on touch supported pc with Windows 8.1. I have managed to show the virtual keyboard when textfield is focused with java switch:
-Dcom.sun.javafx.isEmbedded=true -Dcom.sun.javafx.virtualKeyboard=javafx
I found how to that on JavaFX Virtual Keyboard doesn't show1.
But when the keyboard show's up, it overlapps nodes below the keyboard.
According to what I read, http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/embed.htm, it should't be working like that.
Does anyone have any experience with that kind of problem?
When i run the test application it shows in full screen and embedded virtual keyboard is showing, becasue the textfield has focus. The textfield in this case is not visible until i "hide" the keyboard. I am not sure that this is the right approach so i need help please.
java -Dcom.sun.javafx.isEmbedded=true -Dcom.sun.javafx.virtualKeyboard=javafx application.TestVKB
public class TestVKB extends Application{
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception {
TextField tfComment = new TextField();
tfComment.setPromptText("Enter comment");
BorderPane borderPane = new BorderPane();
borderPane.setBottom(tfComment);
Scene scene = new Scene(borderPane);
stage.setScene(scene);
stage.setMaximized(true);
stage.show();
}
}
After click in field username or password
I would be grateful for any advice. Thanks in advance.
As I've already pointed out in my first answer, the virtual keyboard is embedded in a PopupWindow, created in a different stage, and displayed on top of your current stage.
The option -Dcom.sun.javafx.vk.adjustwindow=true works, moving the main stage so the control is visible and there is no overlapping.
But when this input control is located at the bottom of the main stage, this is moved up to the center of the screen leaving a big empty gap that shows whatever is behind.
This second answer gives a solution to move the main stage just the required distance, without any gap, also taking into account the fade in/out animations of the virtual keyboard.
For starters, in our scene, we add a Button on the center, and the TextField on the bottom. With two controls we can change the focus easily and show/hide the keyboard.
To maximize the stage I'll use getVisualBounds(), so the taskbar can be visible.
private PopupWindow keyboard;
private final Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
private final Rectangle2D bounds = Screen.getPrimary().getBounds();
private final double taskbarHeight=bounds.getHeight()-visualBounds.getHeight();
#Override
public void start(Stage stage) {
TextField tfComment = new TextField();
tfComment.setPromptText("Enter comment");
BorderPane borderPane = new BorderPane(new Button("Click"));
borderPane.setBottom(tfComment);
Scene scene = new Scene(borderPane);
stage.setScene(scene);
stage.setX(visualBounds.getMinX());
stage.setY(visualBounds.getMinY());
stage.setWidth(visualBounds.getWidth());
stage.setHeight(visualBounds.getHeight());
stage.show();
}
We need to find the new stage when it's shown. In the same way as Scenic View, we'll use a deprecated method to get a valid window:
private PopupWindow getPopupWindow() {
#SuppressWarnings("deprecation")
final Iterator<Window> windows = Window.impl_getWindows();
while (windows.hasNext()) {
final Window window = windows.next();
if (window instanceof PopupWindow) {
if(window.getScene()!=null && window.getScene().getRoot()!=null){
Parent root = window.getScene().getRoot();
if(root.getChildrenUnmodifiable().size()>0){
Node popup = root.getChildrenUnmodifiable().get(0);
if(popup.lookup(".fxvk")!=null){
return (PopupWindow)window;
}
}
}
return null;
}
}
return null;
}
We'll call this method when the textfield gets the focus:
...
stage.show();
tfComment.focusedProperty().addListener((ob,b,b1)->{
if(keyboard==null){
keyboard=getPopupWindow();
}
});
}
Once we have the window, we can listen to changes in its position and move the main stage accordingly:
....
stage.show();
//findWindowExecutor.execute(new WindowTask());
tfComment.focusedProperty().addListener((ob,b,b1)->{
if(keyboard==null){
keyboard=getPopupWindow();
keyboard.yProperty().addListener(obs->{
System.out.println("wi "+keyboard.getY());
Platform.runLater(()->{
double y = bounds.getHeight()-taskbarHeight-keyboard.getY();
stage.setY(y>0?-y:0);
});
});
}
});
}
Note that instead of moving up the stage, another option will be resizing it (if there is enough space within the controls).
This will be the case where the textfield gets the focus and the virtual keyboard is fully shown:
Basically, the virtual keyboard is embedded in a PopupWindow, created in a different stage, and displayed on top of your current stage, at the bottom of the screen, no matter where the InputControl that triggers the keyboard is located.
You can see that on the FXVKSkin class:
winY.set(screenBounds.getHeight() - VK_HEIGHT);
But, just inmediately after that, you can find this:
if (vkAdjustWindow) {
adjustWindowPosition(attachedNode);
}
So, there's another command line option that you can use to move the stage so the node (the textfield in this case) will be on the center of the screen and you can type without overlapping it:
-Dcom.sun.javafx.vk.adjustwindow=true
Note that when the textfield loses the focus, the keyboard is hidden and the stage is moved again to its original position:
restoreWindowPosition(oldNode);
I've tested this option successfully, but when you have the textfield at the bottom of the screen, this will move your stage bottom to the center of the screen, leaving a big gap between both stages (you'll see whatever you have on the background).
I've managed to add a listener to the new stage and adjust the position just the necessary. If you are interested I could post it.
EDIT
Note this command line option won't work if the stage is maximized. A simple solution for this is:
Rectangle2D bounds = Screen.getPrimary().getBounds();
stage.setX(bounds.getMinX());
stage.setY(bounds.getMinY());
stage.setWidth(bounds.getWidth());
stage.setHeight(bounds.getHeight());
stage.show();
I liked the solution, but in my case I prefer to move the keyboard using the showed method getPopupWindow i created a listener on textfield and changed the position of the keyboard directly.
textField.focusedProperty().addListener((ob, b, b1) -> {
if (keyboard == null) {
keyboard = getPopupWindow();
keyboard.setHideOnEscape(Boolean.TRUE);
keyboard.setAutoHide(Boolean.TRUE);
keyboard.centerOnScreen();
keyboard.requestFocus();
keyboard.sizeToScene();
}
Platform.runLater(() -> {
keyboard.setY(**NEW_POSITION_OF_KEYBOARD**);
});
});

Weird behavior of two mouse events being triggered infinitely in tooltip code

I am trying to implement a custom tooltip using the javafx.stage.Popup. The sample demo code is:
public class PopupDemo extends Application {
private Popup tooltip;
private final SepiaTone sepiaTone = new SepiaTone();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("PopupDemo");
Label content = new Label();
content.setStyle("-fx-background-color:#FCFBBD; -fx-padding: 5; -fx-border-color: #BFBD3B");
tooltip = new Popup();
tooltip.getContent().add(content);
VBox vbox = new VBox(10);
for (int i = 0; i < 5; i++) {
final Label lbl = new Label("item " + i);
lbl.setStyle("-fx-border-color:darkgray; -fx-background-color:lightgray");
lbl.setMaxSize(80, 60);
lbl.setMinSize(80, 60);
lbl.setAlignment(Pos.CENTER);
lbl.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(final MouseEvent e) {
lbl.setEffect(sepiaTone);
lbl.setStyle("-fx-cursor: hand");
Label content = (Label) tooltip.getContent().get(0);
content.setText(lbl.getText());
tooltip.show(lbl, e.getScreenX(), e.getScreenY());
}
});
lbl.setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
lbl.setEffect(null);
lbl.setStyle("-fx-cursor: default");
tooltip.hide();
}
});
vbox.getChildren().add(lbl);
}
StackPane root = new StackPane();
root.setPadding(new Insets(20));
root.getChildren().add(vbox);
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}
}
When I move the mouse over the labels the popup shows up and it is working great. But in some cases the two mouse event handlers OnMouseEntered and OnMouseExited are being called continuously one after another. One can reproduce this by running provided example, maximising a window and hovering labels continuously.
Is there a way to avoid this? I'm using JavaFX 2.0.1. Thanks.
It's a classic problem: you put mouse at a point, node receives MouseEntered — tooltip appears under the mouse and covers the node triggering MouseExited.
To avoid that you can change tooltip.show(lbl, e.getScreenX(), e.getScreenY()) call to
tooltip.show(lbl, e.getScreenX() + 1, e.getScreenY() + 1);
This is not really an answer, so much as pointers to things you might try or investigate further.
You could look at the implementation of Tooltip Skin and Behavior to see how it handles some of these cases.
The easiest way to implement a custom popup is just to use a Tooltip, style it the way you need using css and use the Tooltip's setGraphic method to add any custom Node content you want.
If you prefer to use your own implementation, I think you need to keep track of whether the popup has been displayed or not, so you don't try to show it if it is already showing, etc. You may also need invoke the hiding of the popup by having a mouse exit handler installed on the popup itself. You also might want a click to dismiss function for the popup by implementing a mouse click handler on the popup. You should also consider whether you should do a straight subclass of Popup or PopupControl, though using Popup as you have is likely more straightforward.

Categories