JavaFX虚拟键盘与节点重叠

Gre*_*ega 5 java virtual-keyboard javafx-8

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

-Dcom.sun.javafx.isEmbedded=true -Dcom.sun.javafx.virtualKeyboard=javafx
Run Code Online (Sandbox Code Playgroud)

我发现在JavaFX虚拟键盘上如何显示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();
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

单击字段用户名或密码后 在此输入图像描述

我会很感激任何建议.提前致谢.

Jos*_*eda 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();
}
Run Code Online (Sandbox Code Playgroud)

当它显示出来时,我们需要找到新的舞台.与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;
}
Run Code Online (Sandbox Code Playgroud)

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

    ...
    stage.show();

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

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

    ....
    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);
                });
            });
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

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

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

虚拟键盘


Jos*_*eda 2

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

你可以在课堂上看到FXVKSkin

winY.set(screenBounds.getHeight() - VK_HEIGHT);
Run Code Online (Sandbox Code Playgroud)

但是,紧接着,您可以发现:

if (vkAdjustWindow) {
    adjustWindowPosition(attachedNode);
}
Run Code Online (Sandbox Code Playgroud)

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

-Dcom.sun.javafx.vk.adjustwindow=true
Run Code Online (Sandbox Code Playgroud)

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

restoreWindowPosition(oldNode);
Run Code Online (Sandbox Code Playgroud)

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

我已经成功地向新舞台添加了一个侦听器,并根据需要调整了位置。如果你有兴趣我可以发布它。

编辑

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

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