【问题标题】:Javafx show virtual keyboardJavafx 显示虚拟键盘
【发布时间】:2017-07-16 23:56:53
【问题描述】:

我不想像Programmatically show/hide virtual keyboard那样隐藏虚拟键盘

OR(如果以上点不可能的话)

我想从虚拟键盘上移除/隐藏/禁用下方(突出显示的绿色左下角)按钮。

我正在使用 Java 8 和 Javafx。


更新 1


我已集成José Pereda's code。隐藏按钮 (.hide) 已成功隐藏。现在我很难一直显示键盘。

问题:

只要有焦点从textarea 出来,键盘就会隐藏。因此,当用户单击Convert Now! 按钮时,键盘会隐藏。我试图通过使用textarea.requestFocus(); 来专注于textarea,但是键盘闪烁(先隐藏然后显示)。

我的目标

除非程序没有终止,否则在任何情况下都不会隐藏键盘。

代码:你也可以在github 上查看我的代码。

package com.binaryname.view;

import java.util.Iterator;

import com.sun.javafx.print.PrintHelper;
import com.sun.javafx.print.Units;
import com.sun.javafx.scene.control.skin.FXVK;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.print.PageLayout;
import javafx.print.PageOrientation;
import javafx.print.Paper;
import javafx.print.Printer;
import javafx.print.PrinterJob;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Path;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.transform.Scale;
import javafx.stage.PopupWindow;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;

public class Main extends Application {

    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 primaryStage) throws Exception {

        primaryStage.setTitle("Binary Name");

        Label helloLbl = new Label("Hello");
        helloLbl.setAlignment(Pos.CENTER);
        helloLbl.setFont(Font.font("Comic Sans MS", FontWeight.BOLD, 68));
        helloLbl.setStyle("-fx-background-color: red;padding: 20px;");
        helloLbl.setTextFill(Color.web("#ffffff"));

        Label myNameLbl = new Label("my name is");
        myNameLbl.setAlignment(Pos.CENTER);
        myNameLbl.setFont(Font.font("Comic Sans MS", 48));
        myNameLbl.setStyle("-fx-background-color: red;padding: 20px;");
        myNameLbl.setTextFill(Color.web("#ffffff"));

        TextArea nameTxtArea = new TextArea();
        nameTxtArea.setWrapText(Boolean.TRUE);
        nameTxtArea.getStyleClass().add("center-text-area");
        nameTxtArea.setFont(Font.font("Comic Sans MS", 28));
        nameTxtArea.setStyle("padding: 20px;");

        Button printBtn = new Button("PRINT");
        printBtn.setId("ipad-grey");
        printBtn.setDisable(Boolean.TRUE);

        Button convertBtn = new Button("Convert Now!");
        convertBtn.setId("ipad-grey");
        convertBtn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                nameTxtArea.requestFocus();
                convertBtn.setDisable(Boolean.TRUE);
                printBtn.setDisable(Boolean.FALSE);
            }
        });

        HBox hBox = new HBox(100);
        hBox.setAlignment(Pos.CENTER);
        hBox.getChildren().addAll(convertBtn, printBtn);

        VBox vBox = new VBox(10);
        vBox.setAlignment(Pos.TOP_CENTER);
        vBox.getChildren().addAll(helloLbl, myNameLbl, nameTxtArea, hBox);
        vBox.setStyle("-fx-background-color: red;margin: 20px;");

        printBtn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                nameTxtArea.requestFocus();
                // Start printing
                print(vBox, nameTxtArea.getText());
                convertBtn.setDisable(Boolean.FALSE);
                printBtn.setDisable(Boolean.TRUE);
                nameTxtArea.setText("");
            }
        });

        Scene scene = new Scene(vBox);
        scene.getStylesheets().add(Main.class.getResource("/style.css").toExternalForm());

        primaryStage.setScene(scene);
        primaryStage.initStyle(StageStyle.UNDECORATED);
        primaryStage.setScene(scene);
        primaryStage.setX(visualBounds.getMinX());
        primaryStage.setY(visualBounds.getMinY());
        primaryStage.setWidth(visualBounds.getWidth());
        primaryStage.setHeight(visualBounds.getHeight());

        adjustTextAreaLayout(nameTxtArea);

        primaryStage.show();

        // attach keyboard to first node on scene:
        Node first = scene.getRoot().getChildrenUnmodifiable().get(0);
        if (first != null) {
            FXVK.init(first);
            FXVK.attach(first);
            keyboard = getPopupWindow();
        }

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

            keyboard.setHideOnEscape(Boolean.FALSE);
            keyboard.setAutoHide(Boolean.FALSE);
            keyboard.centerOnScreen();
            keyboard.requestFocus();

            keyboard.yProperty().addListener(obs -> {

                Platform.runLater(() -> {
                    Double y = bounds.getHeight() - taskbarHeight - keyboard.getY();
                    nameTxtArea.setMaxHeight((bounds.getHeight() - y) * 0.4);
                    nameTxtArea.setMinHeight((bounds.getHeight() - y) * 0.4);
                });
            });

        });     

    }

    public static void main(String[] args) {
        launch(args);
    }

    private void print(Node node1, String text) {
        // Create a printer job for the default printer

        Printer printer = Printer.getDefaultPrinter();
        Paper label = PrintHelper.createPaper("2.5x3.5", 2.5, 3.5, Units.INCH);
        PageLayout pageLayout = printer.createPageLayout(label, PageOrientation.LANDSCAPE, Printer.MarginType.EQUAL);

        PrinterJob job = PrinterJob.createPrinterJob();

        Node node = createFullNode(text);

        double scaleX = pageLayout.getPrintableWidth() / node1.getBoundsInParent().getWidth();
        double scaleY = pageLayout.getPrintableHeight() / node1.getBoundsInParent().getHeight();
        node.getTransforms().add(new Scale(scaleX, scaleY));

        if (job != null) {
            // Print the node
            boolean printed = job.printPage(node);

            if (printed) {
                // End the printer job
                job.endJob();
            } else {
                // Write Error Message
                System.out.println("Printing failed.");
            }
        } else {
            // Write Error Message
            System.out.println("Could not create a printer job.");
        }

        node.getTransforms().remove(node.getTransforms().size() - 1);
    }

    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) {
                            FXVK vk = (FXVK) popup.lookup(".fxvk");
                            // hide the key:
                            vk.lookup(".hide").setVisible(false);
                            return (PopupWindow) window;
                        }
                    }
                }
                return null;
            }
        }
        return null;
    }

    private Node createFullNode(String text) {

        Label helloLbl = new Label("Hello");
        helloLbl.setAlignment(Pos.CENTER);
        helloLbl.setFont(Font.font("Comic Sans MS", FontWeight.BOLD, 68));
        helloLbl.setStyle("-fx-background-color: red;padding: 20px;");
        helloLbl.setTextFill(Color.web("#ffffff"));

        Label myNameLbl = new Label("my name is");
        myNameLbl.setAlignment(Pos.CENTER);
        myNameLbl.setFont(Font.font("Comic Sans MS", 48));
        myNameLbl.setStyle("-fx-background-color: red;padding: 20px;");
        myNameLbl.setTextFill(Color.web("#ffffff"));

        TextArea nameTxtArea = new TextArea();
        nameTxtArea.setWrapText(Boolean.TRUE);
        nameTxtArea.setFont(Font.font("Comic Sans MS", 28));
        nameTxtArea.setStyle("padding: 20px;");
        nameTxtArea.setText(text);
        nameTxtArea.getStyleClass().add("center-text-area");

        HBox hBox = new HBox(1000);
        hBox.setAlignment(Pos.CENTER);

        VBox vBox = new VBox(10);
        vBox.setAlignment(Pos.CENTER);
        vBox.getChildren().addAll(helloLbl, myNameLbl, nameTxtArea, hBox);
        vBox.setStyle("-fx-background-color: red;margin: 20px;");

        vBox.getStylesheets().add(Main.class.getResource("/style.css").toExternalForm());

        return vBox;
    }

    private void adjustTextAreaLayout(TextArea textArea) {
        textArea.applyCss();
        textArea.layout();

        ScrollPane textAreaScroller = (ScrollPane) textArea.lookup(".scroll-pane");
        Text text = (Text) textArea.lookup(".text");


        ChangeListener<? super Bounds> listener = 
                (obs, oldBounds, newBounds) -> centerTextIfNecessary(textAreaScroller, text);
        textAreaScroller.viewportBoundsProperty().addListener(listener);
        text.boundsInLocalProperty().addListener(listener);

    }

    private void centerTextIfNecessary(ScrollPane textAreaScroller, Text text) {
        double textHeight = text.getBoundsInLocal().getHeight();
        double viewportHeight = textAreaScroller.getViewportBounds().getHeight();
        double offset = Math.max(0, (viewportHeight - textHeight) / 2 );
        text.setTranslateY(offset);
        Parent content = (Parent)textAreaScroller.getContent();
        for (Node n : content.getChildrenUnmodifiable()) {
            if (n instanceof Path) { // caret
                n.setTranslateY(offset);
            }
        }
    }
}

【问题讨论】:

    标签: java javafx javafx-8 virtual-keyboard


    【解决方案1】:

    您可以按需显示和隐藏虚拟键盘。

    您只需要提供一个键盘将附加到的节点,它不需要是 TextField。

    显然,您展示了能够在输入控件中键入的虚拟键盘(TextField、TextArea、...),但我将把这部分留给您。

    在不知道你的场景层次结构的情况下,我只选择它上面的第一个节点:

    @Override
    public void start(Stage stage) {
        ...
        stage.setScene(scene);
        stage.show();
    
        // attach keyboard to first node on scene:
        Node first = scene.getRoot().getChildrenUnmodifiable().get(0);
        if (first != null) {
            FXVK.init(first);
            FXVK.attach(first);
        }
    }
    

    这将在显示舞台后立即显示键盘。

    如果您想在任何时候以编程方式关闭它,您只需调用:

    FXVK.detach();
    

    关于隐藏键盘的一个键,这有点棘手,因为键盘放置在弹出窗口中,所以首先你需要掌握它。但是您已经可以找到解决方案,例如 this one。

    下面的 sn -p 会寻找弹出窗口。至于不推荐使用的方法,在JavaFX 9 上它将是一个公共方法(javafx.stage.Windows.getWindows())。

    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) {
                            FXVK vk = (FXVK) popup.lookup(".fxvk");
    
                            return (PopupWindow) window;
                        }
                    }
                }
                return null;
            }
        }
        return null;
    }
    

    一旦你有了虚拟键盘实例,你就可以通过查找找到它的任何节点,基于它们的样式类。幸运的是,所有键都分配了 styleClass key,因此您可以轻松地与它们进行交互。至于隐藏键盘的特定键,这个也有specialhide样式类:

    // hide the key:
    vk.lookup(".hide").setVisible(false);
    

    完整示例代码:

    public class FXVKAlwaysOn extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            Button btn = new Button();
            btn.setText("Say 'Hello World'");
    
            StackPane root = new StackPane();
            root.getChildren().add(btn);
    
            Scene scene = new Scene(root, 1280, 600);
    
            primaryStage.setTitle("Hello World!");
            primaryStage.setScene(scene);
            primaryStage.show();
    
            Node first = scene.getRoot().getChildrenUnmodifiable().get(0);
            if (first != null) {
                FXVK.init(first);
                FXVK.attach(first);
                getPopupWindow();
            }
        }
    
        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) {
                                FXVK vk = (FXVK) popup.lookup(".fxvk");
                                // hide the key:
                                vk.lookup(".hide").setVisible(false);
                                return (PopupWindow) window;
                            }
                        }
                    }
                    return null;
                }
            }
            return null;
        }
    }
    

    【讨论】:

    • 为我工作。有一点是,我怎样才能找到.hide.fxvk 等类的列表?以便将来我可以轻松地操纵它们。
    • 一种方法是查看源代码(即FXVKSkin)并找出应用于节点的样式类。在其他情况下,您可以使用ScenicView,但它通常不适用于弹出窗口。
    • 是的,只要 TextArea 获得焦点,VK 附加节点就会切换到它。 textArea 有一个focusedProperty 监听器,它根据获得/失去的焦点显示和隐藏VK。时间允许的话我会想办法的。
    • 感谢何塞的回复。有没有办法覆盖focusdChangelistner 或类似的东西来获得期望的结果?
    • 不,无法移除监听器,但还有其他选项。
    猜你喜欢
    • 2015-01-02
    • 1970-01-01
    • 2015-01-02
    • 2020-10-09
    • 1970-01-01
    • 2014-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多