I am creating an application, and I want a feature where when the user presses E, it will set the mouse pointer to the center of the screen (using the moveMouse()
method). However, it just gives me an IllegalStateException
.
I have tried using a GlassRobot
instead (from this question with an accepted answer), but that only gives me an IllegalAccessException
instead. What am I doing wrong? Do I need to include something?
IllegalStateException
Note: There is a comment near the bottom
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1082)
Caused by: java.lang.ExceptionInInitializerError
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:465)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
... 5 more
Caused by: java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = main
at javafx.graphics/com.sun.glass.ui.Application.checkEventThread(Application.java:447)
at javafx.graphics/javafx.scene.robot.Robot.<init>(Robot.java:70)
at com.galactify.tiles/com.galactify.tiles.HelloApplication.<clinit>(HelloApplication.java:37) // This is where the Robot object is created
... 11 more
private static final Robot robot = new Robot() ;
private static final Robot robot = com.sun.glass.ui.Application.GetApplication().createRobot() ;
static void onKeyReleased(KeyEvent evt) {
KeyCode key = evt.getCode() ;
out.println(key + " is released") ;
switch (key) {
case F11 -> {
stage.setFullScreen(!isFullscreen) ;
isFullscreen = !isFullscreen ;
}
case C -> {
stage.close() ;
isClosed = true ;
}
case E -> setupInventory() ;
}
}
static void setupInventory() {
robot.mouseMove((double) screenWidth / 2, (double) screenHeight / 2) ;
}
GlassRobot
)The question mentions raising a request to make the GlassRobot
functionality public API. This request was completed years ago in JavaFX 11, and the public API is Robot
(which you are already using in your question).
There is no need to use the non-public GlassRobot
API and there are numerous reasons not to use it.
This operation is permitted on the event thread only; currentThread = main
You have robot
declared as a static member of your application class. Static members are initialized when the class is loaded. Your main application class will be loaded on the main Java thread. But, the error message states the Robot
must be loaded on the JavaFX thread.
Change your declaration to this:
private Robot robot;
Initialize the robot in your start()
method (or some other method that is called on the JavaFX application thread):
@Override
public void start(Stage stage) {
robot = new Robot();
// other app logic
}
Often it is best to minimize static state and initialization in Java applications. One reason is that if the initialization fails and throws an Exception, then the class will fail to load, which can be quite hard to understand (as you may have discovered here). There are other reasons for avoiding static state. This advice applies mainly to static state. Static methods that don't rely on static state, such as those in the Math
class, can sometimes be fine.
If you want to know more about threading in JavaFX, read the Application lifecycle documentation.