JavaFX virtual keyboard overlaps nodes
Asked Answered
G

3

5

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

enter image description here

After click in field username or password enter image description here

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

Gratification answered 16/1, 2015 at 9:28 Comment(4)
it would be useful to have a screenshot of an overlappingSubmultiple
I added a further explanation, because currently I can not upload images due to the lack of reputationGratification
Try to upload an image now.Forename
Thanks. I have uploaded images. What am i missing?Gratification
S
9

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:

Virtual keyboard

Sherwoodsherwynd answered 16/1, 2015 at 22:12 Comment(0)
S
2

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();
Sherwoodsherwynd answered 16/1, 2015 at 17:26 Comment(6)
First of all thanks for the response. I have icluded switch for adjustwindow, but there is no diference. Keyboard is still overlapping. Can you please be so kind and post your solution? Many thanks.Gratification
The reason for that is stage.setMaximized(true). I've edited my answer with a valid solution.Guaiacum
Have tried and it really does work like you have described. Stage is set to the center of screen and leaves gap between keyboard. How did you implement the listener to the new stage? It moves "original" stage up just for the height of the keyboard or resize it?Gratification
Well, it's up to you, you can resize the stage (if you have plenty of space within the controls) or you can move it just the height of the keyboard.Guaiacum
I am trying to figure out where/how to implement listener to the new stage so i will know, that the keyboard is visible/showing but.... Can you give me some directions? Should i be looking in FXVK(Skin) or somewhere else?Gratification
The solution is quite long since require finding the new stage. I'll add it as another answer.Guaiacum
M
0

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


    });     
Masturbation answered 3/5, 2017 at 15:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.