JavaFX虚拟键盘与节点重叠

时间:2015-01-16 09:28:04

标签: java javafx-8 virtual-keyboard

我有一个关于在Windows 8.1上使用触摸支持的电脑上使用虚拟键盘的问题。当使用java开关重点关注textfield时,我已设法显示虚拟键盘:

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

我在JavaFX Virtual Keyboard doesn't show 1上找到了相应的内容。

但是当键盘显示时,它会覆盖键盘下方的节点。

根据我所读到的http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/embed.htm,它不应该像那样工作。

有没有人有这种问题的经验?

当我运行测试应用程序时,它会全屏显示并显示嵌入式虚拟键盘,因为文本字段具有焦点。在这种情况下,文本字段是不可见的,直到我隐藏"键盘。我不确定这是正确的方法所以我需要帮助。

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

点击字段用户名或密码后 enter image description here

如果有任何建议,我将不胜感激。提前谢谢。

3 个答案:

答案 0 :(得分:7)

正如我在第一个回答中已经指出的那样,虚拟键盘嵌入在PopupWindow中,在不同的阶段创建,并显示在当前舞台的顶部。

选项-Dcom.sun.javafx.vk.adjustwindow=true有效,移动主舞台以便控件可见并且没有重叠。

但是当这个输入控制位于主舞台的底部时,它会向上移动到屏幕的中心,留下一个很大的空隙,显示背后的内容。

第二个答案提供了一个解决方案,可以将主舞台移动到所需的距离,没有任何间隙,同时还考虑了虚拟键盘的淡入/淡出动画。

对于初学者,在我们的场景中,我们在中心添加Button,在底部添加TextField。使用两个控件,我们可以轻松更改焦点并显示/隐藏键盘。

要最大化阶段,我将使用getVisualBounds(),因此可以看到任务栏。

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

我们需要在显示时找到新阶段。与Scenic View一样,我们将使用弃用的方法来获取有效窗口:

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

当文本字段获得焦点时,我们将调用此方法:

    ...
    stage.show();

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

一旦我们有了窗口,我们就可以听取其位置的变化并相应地移动主舞台:

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

请注意,不是向上移动舞台,而是另一个选项是调整大小(如果控件中有足够的空间)。

这将是文本字段获得焦点并完全显示虚拟键盘的情况:

Virtual keyboard

答案 1 :(得分:2)

基本上,虚拟键盘嵌入在PopupWindow中,在不同的舞台上创建,并显示在当前舞台的顶部,在屏幕的底部,无论InputControl在哪里触发键盘所在的位置。

您可以在FXVKSkin课程上看到:

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

但是,在此之后,您可以找到:

if (vkAdjustWindow) {
    adjustWindowPosition(attachedNode);
}

因此,您可以使用另一个命令行选项移动舞台,以便节点(本例中为文本字段)位于屏幕的中心,您可以键入而不重叠:

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

请注意,当文本字段失去焦点时,键盘将被隐藏,舞台将再次移动到其原始位置:

restoreWindowPosition(oldNode);

我已经成功测试了这个选项,但是当你在屏幕底部有文本字段时,这会将你的舞台底部移动到屏幕的中心,两个阶段之间留下很大的差距(你会看到任何东西)你有背景)。

我设法在新舞台上添加一个听众,并根据需要调整位置。如果你有兴趣我可以发布它。

修改

如果舞台最大化,请注意此命令行选项不起作用。一个简单的解决方案是:

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

答案 2 :(得分:0)

我喜欢这个解决方案,但在我的情况下,我更喜欢使用show方法移动键盘 getPopupWindow 我在textfield上创建了一个监听器并直接改变了键盘的位置。

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


    });