JavaFX virtual keyboard overlaps textfield component - javafx

I have a question about using a virtual keyboard on touch supported pc with ubuntu.I have managed to show the virtual keyboard when textfield is focused on java :
-Dcom.sun.javafx.isEmbedded=true
-Dcom.sun.javafx.touch=true
-Dcom.sun.javafx.virtualKeyboard=javafx
-Dcom.sun.javafx.vk.adjustwindow=true
But when the keyboard show's up, it overlaps text fields below the keyboard.
According to official documentation http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/embed.htm
"The virtual keyboard is shown automatically when a text input field is in focus. Note that the control that is associated with the keyboard remains visible when the keyboard is displayed. There is no need to push the parent stage up. The keyboard slides in from the bottom area pushing the parent stage up in order to keep the control that the keyboard is associated with visible on the screen."
It should automatically push the text-field upward and make it visible.
I tried implementing the solution from JavaFX virtual keyboard overlaps nodes, but it was not working as per requirement.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) {
TextField textField = new TextField();
textField.setPromptText("Enter comment");
BorderPane borderPane = new BorderPane(new Button("Click"));
borderPane.setBottom(textField);
Scene scene = new Scene(borderPane,1850,1200);
stage.setScene(scene);
stage.show();
}
}
JavaFX virtual keyboard application- keyboard hidden
JavaFX virtual keyboard application- keyboard open
I would be grateful for any suggestions or solutions.
Thanks in advance.

Related

How to Access JavaFX Virtual Keyboard (FXVK) Using Open JDK 15 or beyond?

I use the javafx virtual keyboard with open jdk 8. At times I have to access the virtual keyboard to prevent it from displaying when certain text fields get focus. An example of this is a screen where an operator has to scan in multiple barcodes. This virtual keyboard gets in the way. With open jdk 8 we were able to disable the virtual keyboard like this:
FXVK.detach(); //after importing "com.sun.javafx.scene.control.skin.FXVK"
We are now upgrading to open jdk 15 and building our UI with gradle. "com.sun.javafx.scene.control.skin.FXVK" is no longer accessible with a modular project with gradle. I don't believe using a different virtual keyboard is an option so can anyone explain how to access this FXVK class after java 8?
Is there a way to use --add-exports or --patch-module with a JAR to patch JavaFX to gain access to the internal class?
Below is the code for a sample project that shows this problem.
This is the JavaFX Application class that simply displays a text field and shows the code I could use with java 8 to not show the virtual keyboard.
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();
}
}
});
}
}
Then I needed to add a wrapper class to have the virtual keyboard show up. Please note that most of the time I do use the virtual keyboard when text fields get focus, it's other times where I need to be able to programmatically disable it during certain situations.
The wrapper class:
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);
}
}
Let me know if you need anything else such as the build.gradle file however this is mostly just an issue using java 9 or beyond.
The FXVK class still exists in the same package, so the only issue is that its package is not exported by the javafx.controls module. If you must use this internal class, then you can pass an appropriate --add-exports JVM argument both at compile-time and at run-time.
Here's a simple application that calls 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();
}
}
Assuming you put the Main.java file in your working directory, you can compile it with:
javac -p <path-to-fx> --add-modules javafx.controls --add-exports javafx.controls/com.sun.javafx.scene.control.skin=ALL-UNNAMED Main.java
And run it with:
java -p <path-to-fx> --add-modules javafx.controls --add-exports javafx.controls/com.sun.javafx.scne.control.skin=ALL-UNNAMED Main
If your code is modular then you can get rid of the --add-modules and you must change ALL-UNNAMED to the name of your module. Plus, make sure to launch your application via --module (or -m). Note the -p above is shorthand for --module-path.
If you use a build tool (e.g., Maven, Gradle, etc.), then you'll have to lookup how to set these JVM arguments for that tool. You'll also have to take into account how you deploy your application. For instance, if you use jpackage then you can use its --java-options argument to set the --add-exports option for when your application is launched.
You may also need to tell your IDE that you are giving yourself access to the internal package. Otherwise, your IDE will likely yell at you for trying to use an inaccessible type.

How to block events to the underlying scene but not the window when a Dialog is open?

Basically, I have an application that opens mostly modal dialogs as I dont want the user to be able to continue working in the main app while a dialog is open. However, Modality.APPLICATION_MODAL as well as Modality.WINDOW_MODAL both also prevent minimizing and maximizing windows. That is a problem when a dialog gets triggered by an non-user event and the user has minimized the window already -> he cant open it again.
Now I have a sort of workaround that opens the dialog manually on the main Screen of the user. I could also simply make the dialog non-modal if the app is minimized, but then he could work in the application while ignoring the dialog. Both solutions are not particularly pretty and not exactly what I want.
I know its a "feature" but is there really no way to interact with the window but not the scene of the owner Stage? Perhaps a way to block user events to the scene without using modality? Would seem like a pretty common use case to me.
Here is a minimalistic code example:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.ScrollPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class DialogDemo extends Application {
#Override
public void start(Stage primaryStage) {
Stage mainStage = new Stage();
Button showDialogBtn = new Button("show Dialog");
showDialogBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Dialog<ButtonType> dialog = new Dialog<ButtonType>();
dialog.initStyle(StageStyle.DECORATED);
dialog.initOwner(mainStage);
//prevents mainStage from being resized, mini-/maximized and closed
dialog.initModality(Modality.WINDOW_MODAL);
dialog.getDialogPane().getButtonTypes().add(ButtonType.CLOSE);
dialog.show();
}
});
ScrollPane pane = new ScrollPane(showDialogBtn);
pane.setMinSize(600, 480);
mainStage.setScene(new Scene(pane));
mainStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

JemmyFX interactions with a control in a dialog fail intermittently **on Linux**

My JavaFX application creates a dialog as a second Stage and my JemmyFX tests intermittently fail to click controls in that dialog.
Failures occur at a rate of about 10% on my Ubuntu Linux workstation, but this works flawlessly on Windows.
The proximal cause of the failure seems to be that JemmyFX is clicking the mouse in the wrong places. I dug into this, and the bad click coordinates seem to be caused by incorrect window coordinates coming from the Window object that owns the Scene.
So, I created a minimal application and test that demonstrates the problem, and it actually fails at an even higher rate than my real application (about 50%).
Here is the application:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;
public class MySmallApplication extends Application {
public void start(Stage primaryStage) {
class MyDialog extends Stage {
public MyDialog() {
setTitle("My Dialog");
ComboBox comboBox = new ComboBox();
comboBox.getItems().add("apple");
comboBox.getItems().add("pear");
comboBox.getItems().add("banana");
comboBox.setId("click-me");
setScene(new Scene(comboBox));
sizeToScene();
}
}
Button button = new Button("Show Dialog");
button.setOnAction((event) -> {
new MyDialog().showAndWait();
});
primaryStage.setScene(new Scene(button));
primaryStage.setTitle("My Small Application");
primaryStage.show();
}
}
Here is the test:
import javafx.application.Application;
import javafx.scene.control.ComboBox;
import javafx.stage.Window;
import org.jemmy.fx.AppExecutor;
import org.jemmy.fx.SceneDock;
import org.jemmy.fx.control.ComboBoxDock;
import org.jemmy.fx.control.LabeledDock;
import org.jemmy.resources.StringComparePolicy;
import org.junit.BeforeClass;
import org.junit.Test;
import MySmallApplication;
public class WindowBugTest3 {
#BeforeClass
public static void launch() throws InterruptedException {
AppExecutor.executeNoBlock(MySmallApplication.class);
Thread.sleep(1000);
}
#Test
public void testWindowPosition() throws InterruptedException {
SceneDock sceneDock = new SceneDock();
new LabeledDock(
sceneDock.asParent(),
"Show Dialog",
StringComparePolicy.EXACT).mouse().click();
Thread.sleep(1000);
SceneDock dialogSceneDock = new SceneDock(
"My Dialog",
StringComparePolicy.EXACT);
ComboBoxDock comboBoxDock = new ComboBoxDock(
dialogSceneDock.asParent(), "click-me");
comboBoxDock.selector().select("pear");
}
}
I don't really want to develop my tests on Windows.
I observed all of this with recent fetches of JemmyFX (8, 8u, 8u-dev) compiled and run on Java8u101 on Ubuntu 14.04.
It seems that it is a bug in JavaFX (https://bugs.openjdk.java.net/browse/JDK-8166414). It can't be resolved on JemmyFX side.
P.S. It is highly unlikely that it will be fixed in observable time. So I may only suggest to use some ugly workaround like restoring correct dialog coordinates after receiving incorrect ones (e.g. by additional centerOnScreen() on the second invocation of coordinate property listener).

JavaFX Application Menu

So I've looked around a fair bit, but I've not been able to find any information on how to make an application menu in JavaFX.
I've seen a project 'Jayatana' which seems to allow applications to have proper application menus in Ubuntu using Intellij at least (as an example).
I've also seen a few suggestions that using something like the following will work for OS X users:-
final List<MenuBase> menus = new ArrayList<>();
menus.add(GlobalMenuAdapter.adapt(menu));
Toolkit.getToolkit().getSystemMenu().setMenus(menus);
And there is also the NSMenuFX project, again for OS X.
And I've also seen the java-gnome project which I think only works for Swing.
But what I'd really like is some way of making application menus, preferably in a non-OS specific manner.
I'm happy to use a third party jar or whatever which does the heavy lifting but really, does anything like this exist?
At this point would my best bet be using Swing to create the shell of the JavaFX application and use methods which will integrate application menus with Swing instead? If that's the case, is there something that can do this automatically from JavaFX and handle the switching of the differing implementations?
edit
In the end, I simply used a combination of both Swing and JavaFX. I put the JavaFX app inside which allowed me to use the application menus which already work in Swing.
Not ideal, but it did work.
I think you are just looking for MenuBar.useSystemMenuBarProperty(). If you call this method on a menu bar, then if the platform supports system menus (e.g. OS X) the menu will not appear in the scene graph but will be used as the system menu.
SSCCE:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class SystemMenuExample extends Application {
#Override
public void start(Stage primaryStage) {
MenuBar menuBar = new MenuBar();
Menu menu = new Menu("File");
MenuItem quit = new MenuItem("Quit");
quit.setOnAction(e -> Platform.exit());
menu.getItems().add(quit);
menuBar.getMenus().add(menu);
menuBar.setUseSystemMenuBar(true);
BorderPane root = new BorderPane();
root.setTop(menuBar);
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The solution provided by James_D is the standard way of dealing with this in JavaFX but this solution does not work on the Mac, e.g., if you plan to internationalize your application. The Mac introduces some default menu items which you cannot properly deal with that way. That's where the NSMenuFX project comes into play.
NSMenuFX helps you to
Customize the auto-generated application menu of your JavaFX app
Automatically use the same menu bar for all stages
Create common OS X menus like the Window menu
If you can live with the deficiencies of the JavaFX solution use it, if not have a look at NSMenuFX or any of the other projects mentioned for Linux.
This is my code. Howe can i add this to my below code. After choosing start, then i want to run the game
private static final double SCREENWIDTH = 615.0;
private static final double SCREENHEIGHT = 635.0;enter code here
private GridPane root = new GridPane();
private Scene scene = new Scene(root);
private Stage primaryStage;
private GameController controller;
private boolean gewonnen;
private boolean pauze;
private int opstartSeconden;
private int aantalLevels;
private List<Level> levels;
public static void main(String args[]) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws NoPathPossibleException, StartAndEndAreThereSameException {
controller = new GameController(root, scene);// game controler wordt gemaakt
new Thread(this).start(); // we starten het spel in een nieuwe thread. we
this.primaryStage = primaryStage;
primaryStage.setTitle("HapMan9000");
primaryStage.setWidth(SCREENWIDTH);
primaryStage.setHeight(SCREENHEIGHT);
primaryStage.setResizable(false);
primaryStage.setScene(scene);
primaryStage.setOnCloseRequest(e -> closeProgram());
scene.setCursor(Cursor.NONE);
primaryStage.show();
levels = new ArrayList<>();
}
/**
* Zorgt ervoor dat het spel in zijn geheel wordt afgesloten.
*/
private void closeProgram() {
Platform.exit();
System.exit(0);
}
public void spelPauzeren() {
pauze = true;
}

spanish accented characters inside a JavaFX text field

I'm developing an application in Spanish, but in the menus and the text I have to put accented characters but this does not display correctly when I run the application.
For a example, in the code it is
final MenuItem noEffects = new MenuItem("reiniciar selección");
but after running the application it is displayed as
reiniciar selecci?n
How can I display the Spanish text correctly?
Edit:
this is a test code (same issue in the main code)
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hóla mundo");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Answer taken from OP and edited to remove spelling mistakes and improve formatting. Removed the answer from there and put it here as CW.
EDIT: Finally I solved this issue, I had to configure the encoding format in IntelliJ, which is made doing the following steps:
Go to File > Other Settings > Default Settings
There in the left panel select Edit > File encoding
On the right side of the window select "windows-1252" for encoding in IDE Encoding, Project Encoding and Default encoding for properties file.

Resources