JavaFX virtual keyboard overlaps nodes

I have a question about using a virtual keyboard on a touch PC running Windows 8.1. I managed to show the virtual keyboard when the text field is focused on the java switch:

-Dcom.sun.javafx.isEmbedded=true -Dcom.sun.javafx.virtualKeyboard=javafx 

I found that JavaFX Virtual Keyboard does not display 1 .

But when the keyboard appears, it overlaps the nodes under the keyboard.

According to what I read, http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/embed.htm , it should not work like that.

Does anyone have any experience with this issue?

When I run the test application, it is displayed in full screen mode and the built-in virtual keyboard is displayed because the text field has focus. The text box in this case is not displayed until I hide the keyboard. I am not sure if this is the right approach, so I need help.

 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(); } } 

enter image description here

After clicking in the username or password field enter image description here

I would be grateful for any advice. Thanks in advance.

+5
source share
3 answers

As I pointed out in my first answer, the virtual keyboard is built into PopupWindow , created at another stage, and is displayed on top of the current scene.

The -Dcom.sun.javafx.vk.adjustwindow=true option works by moving the main scene so that the control is visible and there is no overlap.

But when this input control is located at the bottom of the main cascade, it moves to the center of the screen, leaving a large blank space that indicates what it costs.

This second answer gives the decision to move the main scene only to the required distance without any gap, also taking into account the fade in / out animation of the virtual keyboard.

First, in our scene we will add a Button to the center, and a TextField to the bottom. With two controls, we can easily change focus and show / hide the keyboard.

To maximize the scene, I use getVisualBounds() , so the taskbar may 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 a new stage when it will be shown. Just like Scenic View , we will use the legacy method to get the correct 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 will call this method when the text field receives focus:

  ... stage.show(); tfComment.focusedProperty().addListener((ob,b,b1)->{ if(keyboard==null){ keyboard=getPopupWindow(); } }); } 

As soon as a window appears, we can listen to the changes in its position and accordingly move the main stage:

  .... 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 around the scene, another parameter will change its size (if there is enough space in the controls).

This will be the case when the text field receives focus and the virtual keyboard is fully displayed:

Virtual keyboard

+7
source

Basically, a virtual keyboard is built into PopupWindow , created at another stage, and is displayed at the top of the current stage, at the bottom of the screen, regardless of where the InputControl that launches the keyboard is located.

You can see that in the FXVKSkin class:

 winY.set(screenBounds.getHeight() - VK_HEIGHT); 

But right after that you can find this:

 if (vkAdjustWindow) { adjustWindowPosition(attachedNode); } 

So, there is another command line option that you can use to move the scene so that the node (text box in this case) will be in the center of the screen, and you can enter it without blocking it:

 -Dcom.sun.javafx.vk.adjustwindow=true 

Note that when the text field loses focus, the keyboard is hidden and the step moves back to its original position:

 restoreWindowPosition(oldNode); 

I have successfully tested this option, but when you have a text box at the bottom of the screen, it will move your stage bottom to the center of the screen, leaving a large gap between both stages (you will see that you are in the background).

I managed to add a listener to a new stage and adjust the position only if necessary. If you're interested, I can post it.

EDIT

Please note that this command line option will not work if the step is maximum. A simple solution for this:

 Rectangle2D bounds = Screen.getPrimary().getBounds(); stage.setX(bounds.getMinX()); stage.setY(bounds.getMinY()); stage.setWidth(bounds.getWidth()); stage.setHeight(bounds.getHeight()); stage.show(); 
+2
source

I liked the solution, but in my case I prefer to move the keyboard using the getPopupWindow method shown , I created a listener in the text box and directly changed the keyboard position.

 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**); }); }); 
0
source

Source: https://habr.com/ru/post/1211234/


All Articles