如何使用 Open JDK 15 或更高版本访问 JavaFX 虚拟键盘 (FXVK)?

Rya*_*van 2 javafx virtual-keyboard java-15

我在打开的 jdk 8 中使用 javafx 虚拟键盘。有时我必须访问虚拟键盘,以防止它在某些文本字段获得焦点时显示。操作员必须扫描多个条形码的屏幕就是一个例子。这个虚拟键盘很碍事。使用 open jdk 8,我们可以像这样禁用虚拟键盘:

FXVK.detach(); //导入“com.sun.javafx.scene.control.skin.FXVK”后

我们现在正在升级到 open jdk 15 并使用 gradle 构建我们的 UI。“com.sun.javafx.scene.control.skin.FXVK”不再可以通过带有 gradle 的模块化项目进行访问。我不相信使用不同的虚拟键盘是一种选择,所以任何人都可以解释如何在 java 8 之后访问这个 FXVK 类吗?

有没有办法使用 --add-exports 或 --patch-module 与 JAR 来修补 JavaFX 以访问内部类?

下面是显示此问题的示例项目的代码。

这是 JavaFX 应用程序类,它仅显示一个文本字段并显示我可以与 java 8 一起使用以不显示虚拟键盘的代码。

package com.test.sampleapp.application;

////not accessible in java 15
//import com.sun.javafx.scene.control.skin.FXVK;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application{

    public static void main(String[] args)
    {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) throws Exception 
    {
        Label label = new Label("Text field below");
        TextField textField = new TextField();
        
        VBox vbox = new VBox(label);
        vbox.getChildren().add(textField);
        
        Scene scene = new Scene(vbox);
        primaryStage.setScene(scene);
        primaryStage.show();
        
        textField.focusedProperty().addListener(new ChangeListener<Boolean>()
        {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean   oldValue,
                    Boolean newValue)
            {
                // If focused
                if (newValue)
                {
                    //Need this to disable the virtual keyboard when using a textfield with scanning
                    //FXVK.detach();
                }
                
            }
        }); 
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我需要添加一个包装类来显示虚拟键盘。请注意,大多数时候,当文本字段获得焦点时,我确实会使用虚拟键盘,但有时我需要能够在某些情况下以编程方式禁用它。

包装类:

package com.test.sampleapp.application;

import java.lang.reflect.Method;

public class AppWrapper 
{   
    public static void main(String[] args) throws Exception 
    {  
        Class<?> app = Class.forName("com.test.sampleapp.application.Main");         
        Method main = app.getDeclaredMethod("main", String[].class);     
        System.setProperty("com.sun.javafx.isEmbedded", "true"); 
        System.setProperty("com.sun.javafx.touch", "true");          
        System.setProperty("com.sun.javafx.virtualKeyboard", "javafx");     
        Object[] arguments = new Object[]{args};
        main.invoke(null, arguments);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您需要其他任何内容(例如 build.gradle 文件),请告诉我,但这主要只是使用 java 9 或更高版本的问题。

Sla*_*law 7

该类FXVK仍然存在于同一个包中,因此唯一的问题是模块未导出其包javafx.controls。如果必须使用这个内部类,那么您可以--add-exports在编译时和运行时传递适当的 JVM 参数。

这是一个简单的应用程序,它调用FXVK#detach()

// Will fail at compile-time if the '--add-exports` argument is not
// passed to 'javac'
import com.sun.javafx.scene.control.skin.FXVK;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        var root = new StackPane(new Label("Hello, World!"));
        primaryStage.setScene(new Scene(root, 600, 400));
        primaryStage.show();

        // Will fail at run-time if the '--add-exports' argument is
        // not passed to 'java'
        FXVK.detach();
    }
}
Run Code Online (Sandbox Code Playgroud)

假设您将该Main.java文件放在工作目录中,您可以使用以下命令编译它:

javac -p <path-to-fx> --add-modules javafx.controls --add-exports javafx.controls/com.sun.javafx.scene.control.skin=ALL-UNNAMED Main.java
Run Code Online (Sandbox Code Playgroud)

并运行它:

java -p <path-to-fx> --add-modules javafx.controls --add-exports javafx.controls/com.sun.javafx.scene.control.skin=ALL-UNNAMED Main
Run Code Online (Sandbox Code Playgroud)

如果您的代码是模块化的,那么您可以删除--add-modules,并且必须更改ALL-UNNAMED为模块的名称。--module另外,请确保通过(或)启动您的应用程序-m。注意-p上面是 的简写--module-path

如果您使用构建工具(例如 Maven、Gradle 等),那么您必须查找如何为该工具设置这些 JVM 参数。您还必须考虑如何部署应用程序。例如,如果您使用jpackagethen 您可以使用其--java-options参数来设置--add-exports应用程序启动时的选项。

您可能还需要告诉 IDE 您正在授予自己访问内部包的权限。否则,您的 IDE 可能会因为您尝试使用无法访问的类型而对您大喊大叫。