JavaFX error when trying to remove shape - java

I'm trying to remove a Rectangle from my window if it is moved to be inside of a certain part of the screen.
This is the error that I got:
Exception in thread "Thread-1539" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-1539
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:238)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:400)
at javafx.scene.Parent$1.onProposedChange(Parent.java:245)
at com.sun.javafx.collections.VetoableObservableList.remove(VetoableObservableList.java:172)
at com.sun.javafx.collections.ObservableListWrapper.remove(ObservableListWrapper.java:263)
at com.sun.javafx.collections.VetoableObservableList.remove(VetoableObservableList.java:179)
at MovementSample$HandListener.onFrame(MovementSample.java:136)
at com.leapmotion.leap.LeapJNI.SwigDirector_Listener_onFrame(LeapJNI.java:495)
This is the snippet of code that cause the issue:
if(areOverlapping(sauceRectangle, pizzaInside)) {
if(isHolding == null) {
Group g = (Group) scene.getRoot().getChildrenUnmodifiable().get(1);
g.getChildren().remove(sauceRectangle);
}
}
where areOverlapping() is just a method that checks some logic - the issue isn't there.
My question is this: How do I remove a rectangle from my screen if I have the scene. Also, what did I do wrong in my code?

The error says it
IllegalStateException: Not on FX application thread
You are trying to do an operation which should be done on JavaFX Application thread and you are not on it.
In order to execute things on JavaFX Application thread, surround them with Platform.runLater
Platform.runLater(new Runnable() {
#Override
public void run() {
//Code to be executed on JavaFX App Thread
}
});
For more information on Modifying UI components in JavaFX

Related

Open Eclipse Wizard or Eclipse MessageDialog in New Thread

I want to open an Eclipse Wizard or MessageDialog in a new thread, but somehow I always get an exception like this one:
Exception in thread "Thread-7" org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(SWT.java:4491)
at org.eclipse.swt.SWT.error(SWT.java:4406)
at org.eclipse.swt.SWT.error(SWT.java:4377)
at org.eclipse.swt.widgets.Widget.error(Widget.java:482)
at org.eclipse.swt.widgets.Shell.<init>(Shell.java:266)
at org.eclipse.swt.widgets.Shell.<init>(Shell.java:362)
at org.eclipse.jface.window.Window.createShell(Window.java:486)
at org.eclipse.jface.window.Window.create(Window.java:429)
at org.eclipse.jface.dialogs.Dialog.create(Dialog.java:1096)
at org.eclipse.jface.window.Window.open(Window.java:792)
at org.eclipse.jface.dialogs.MessageDialog.open(MessageDialog.java:330)
at de.uka.ipd.sdq.beagle.gui.GuiController$DialogPolling.run(GuiController.java:126)
at java.lang.Thread.run(Thread.java:745)
when using code like this:
/**
* Opens up the dialog displaying the actions "pause", "continue", and "abort" to the
* user. These actions are regarding the analysis.
*/
private void engageDialog() {
final String dialogTitle = "Beagle Analysis is Running";
final String dialogMessage = "Beagle Analysis is running.";
final String[] buttonLabels = {"Abort", "Pause"};
this.messageDialog =
new MessageDialog(this.shell, dialogTitle, null, dialogMessage, MessageDialog.INFORMATION, buttonLabels, 0);
new Thread(new DialogPolling()).start();
}
private class DialogPolling implements Runnable {
#Override
public void run() {
final int buttonClick = GuiController.this.messageDialog.open(); // line 126
if (buttonClick == 0) {
System.out.println("User clicked 'Abort'.");
}
if (buttonClick == 1) {
System.out.println("User clicked 'Pause'.");
}
}
}
This is from GuiController and line 126 is marked. Scroll to the right if you can't see the line number.
How can I open a Wizard or a MessageDialog in a new thread?
All wizards, dialogs, ... must be opened in the single SWT UI thread. You can use the Display.syncExec call in another thread to run the dialog open in the UI thread.
Display.getDefault().syncExec(runnable);
Your Runnable can call the dialog open and save the buttonClick value somewhere that you can access when syncExec returns.
GUI systems are usually design as single thread because its almost impossible to write multi thread GUI system. There is to many user interactions and too many events.
Thats why GUI framework usually create his own dedicated thread and all GUI activity is going in this thread. For example Swing has its AWT thread. If long running operation is executing in this thread, it causes freeze of the program (program doesn't react to user input). If you want to avoid this, you must run your logic in different thread. But only your logic, not the GUI actions!
There are some useful classes to solve this issues - like SwingWorked, that is design to run lengthy GUI-interaction tasks in a background thread.
.

JavaFx/ Swing window does not open after update to Java 1.8u40

We have an javafx application developed mainly in java 1.7 and tested in 1.8. It was running fine until java 1.8u35. Now we discovered, JavaFx windows are not going to open in 1.8u40 after upgrade. Even worse, the modal windows are blocking the entire tab/ browser of being used. So the user is just able to close the browser using the task manager.
We use javafx.embed.swing.JFXPanel to embed jfx-code into swing legacy code.
I have completely no clue what might be the problem, as there are no errors displayed in client's java console.
UPDATE:
I reviewed the known issues list for java1.8 here. The only thing I would probably link to our issue is this bug:
BUG-RT-32597: The SwingNode class does not support High DPI displays.
So I tried lowering the screen resolution (1280x1024 to 800x600) but without success.
Does anyone faced a similar issue before and knows what might help?
UPDATE:
I tried to better track down the problem but with not much luck.
To make it more visible, this is basically whats going on on window loading:
public static void initWindow(JDialog dialog){
final JFXPanel jfx = new JFXPanel();
Platform.runLater(new Runnable() {
public void run() {
System.out.println("JFXPanel");
}
});
Runnable r = new Runnable() {
public void run() {
AnchorPane root = new AnchorPane;
//... do some content loading
Scene scene = new Scene(root,width,height);
System.out.println("test");
}
};
dialog.add(jfx);
System.out.println("added jfx panel.");
dialog.pack();
System.out.println("packed jfx panel.");
dialog.setLocationRelativeTo(null);
System.out.println("loaded.");
}
I thought execution is going to stop somewhere, but its running through the entire function as usual. Nevertheless the window is not showing up.
UPDATE:
Not completely correct, my last comment, as I found out:
Around the above function, the following happens:
initWindow(this); //this is extending java.swing.JDialog
System.out.println("this comment is printed to console");
super.setVisible(true); //this is not executed properly. if removed, browser will not be blocked, but window doesnt show up either
System.out.println("this comment is not printed to console";
So, in general, there is the JDialog which gets packed with a JfxPanel. When calling setVisible() method from the JDialog class, the Application gets blocked but the window doesnt show up. Actually, in the thumbnail screen (alt+tab) it is shown as a container inside the application.
When removing the setVisible call, the browser does not get blocked, but also the window does not show up. Unfortunately, I did not find the JDialog class code to look up, what's going on inside setVisible().
Any ideas, what might be wrong with our setup or the setVisible method?
We had a similar problem. While comparing the Java sources of 1.8.0_31 and 1.8.0_45 we found out that there were some changes in the JFXPanel source code introduced with 1.8.0_45 that may cause problems in the following situation:
initialize modal JDialog with JFXPanel (executed on Swing's EDT)
initialize and set FX scene on JFXPanel in FX task (executed on FX Thread)
wait for FX task to be finished (wait on EDT)
pack() and show() JDialog (continued on EDT, blocks program execution)
continue with program execution after user closed JDialog (on EDT)
We use this workflow in order to wait for some user input being shown in a new modal JDialog and continue normal programm execution on EDT afterwards.
In 1.8.0_31, the preferred size of JFXPanel seems to be set in FX thread which allows JDialog.pack() to determine the correct bounds.
In 1.8.0_45, the preferred size of JFXPanel seems to be set not in FX thread anymore but in EDT after all pending AWT events are executed. So, when (4) is executed, JDialog.pack() does not know about the preferred size of the scene. As a consequence, the dialog has no content, or does not show up if undecorated as described in the original question above.
Here is a complete example to reproduce the different behaviour:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// create JDialog on EDT
final JDialog dialog = new JDialog((JDialog)null, "JDialog");
// initialize FX platform and create JFXPanel
final JFXPanel jfxPanel = new JFXPanel();
// add resize listener for JFXPanel
jfxPanel.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// not called in 1.8.0_45
System.out.println("JFXPanel.getSize(): "+jfxPanel.getSize());
}
});
// set FX Scene on JFXPanel and wait until finished
runAndWait(new Runnable() {
public void run() {
Text text = TextBuilder.create().text("JavaFx content").y(20).build();
Group root = new Group(text);
Scene scene = new Scene(root);
jfxPanel.setScene(scene);
}
});
// show undecorated modal JDialog with FX content
System.out.println("JFXPanel.getPreferredSize(): "+jfxPanel.getPreferredSize());
dialog.setUndecorated(true);
dialog.add(jfxPanel);
dialog.pack();
dialog.setModal(true);
System.out.println("JDialog.setVisible()");
dialog.setVisible(true);
}
});
}
private static void runAndWait(Runnable r) {
try {
FutureTask<Object> task = new FutureTask<Object>(r, null);
Platform.runLater(task);
task.get();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
When running this program, componentResized() is called only in 1.8.0_31 but not in 1.8.0_45.
A possible fix while keeping the synchronous program workflow on EDT is to replace JDialog.pack() with JDialog.setSize(...), e. g. by setting a constant size or by using the size of the FX scene that could be determined using root.getBoundsInLocal().
I encountered the same behaviour described by #Peter using 1.8.0_121.
I was able to get dialog.pack() to work using a window listener.
dialog.addWindowListener( new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
((JDialog)e.getSource()).pack();
}
});

Thread pool for async tasks?

I'm using JFace to write a simple file-explorer application. The application's logic can be simplified as:
Display contents of a folder in a TableViewer.
Whenever a folder item gets double-clicked, async-load (to keep UI responsive) its contents and display it.
So in my opnion, there are at least 2 threads get involved: a) the UI thread and b) the background thread that fetches contents of a folder.
What really bothers me here is how does the two threads communicate and do I have to 'invent the wheel'? To be more specific:
How to tell the background thread when an item gets double-clicked? I suppose I need a task queue shared between the two threads or does JFace already provides some async-task mechanism?
How to tell the UI thread that the data have arrived and repaint the table? Which one to choose, asyncexec or syncexec?
What I would usually do is something like this:
// On double-click, start a new thread
new Thread(new Runnable()
{
#Override
public void run()
{
// Get your new data in this thread
final MyFancyDataObject data = SomeOtherClass.goAndGetMyData();
// Update the GUI, this is the safe way to do it from a non-gui-thread
Display.getCurrent().asyncExec(new Runnable()
{
public void run()
{
GuiClass.updateContent(data);
}
});
}
}).start();

Thread in JME doesn't work

In JME I try to use threading but when I run the program the function never starts.
I have a server socket who is listening to input from Netbeans.
Listener
while (isRunning) {
//Reads and prints the input
String receivedString = (String) in.readObject();
System.out.println(receivedString);
String[] parts = receivedString.split(";");
if(parts[0].equals("craneCon"))
{
final int containerId = Integer.parseInt(parts[1]);
m.enqueue(new Callable<Spatial>(){
public Spatial call() throws Exception{
m.removeContainersFromMaritime(containerId);
return null;
}
});
}
So in the main there is the function removeContainersFromMaritime
public void removeContainersFromMaritime(final int idContainer)
{
Node container = Maritime.listOfContainers.get(idContainer);
martime.detachChild(Maritime.listOfContainers.get(idContainer));
seagoingcrane.attachChild(Maritime.listOfContainers.get(idContainer));
container.setLocalTranslation(0,5,0);
System.out.println(Maritime.listOfContainers.get(0).getWorldTranslation().z);
}
The connection is alright but the method is never executed. How can I fix this?
jMonkeyEngine uses a swing-style threading model where there is a single render thread that does all the work. Any changes to the scene graph have to be done from that render thread.
To get into the render thread you can implement AppStates, Controls or you can enqueue Callables which are then executed on the render thread in a similar way to Swing's invokeLater.
The code snippet you posted looks about right, so assuming m is your running jME3 SimpleApplication then m.enqueue() will cause the enqueued callable to be executed next time around the render loop (i.e. at the start of the next frame).
If you are not seeing it executed then either:
Your application is not running
You created more than one application and enqueued it to the wrong one
The code is actually running and you just think it isn't.
Stepping through the code in the debugger and/or adding debug statements (for example breakpoint inside removeContainersFromMaritime to see if it is actually called should allow you to narrow this down.
I might be missing something but what is "m" in m.enqueue(...)?
I'm guessing it is an executor service of some sort and it's probably where the problem lies.
You could try instead:
new Thread() {public void run()
{
m.removeContainersFromMaritime(containerId);
}}.start();
It will at least show you if the problem is coming from "m" as an executor.

how to stop "JavaFX Application Thread"

I have a simple console application which sometimes need to perform graphics operations, for those I'm using JavaFx framework (there are some functions that I need like the css styling for text )
I simply generate some shapes and text into an hidden scene then save those on file and that's all,
I know that to work with JavaFx I have to pass graphics operations to the JavaFx thread, but when everything is done and I have to close the application (after some hours) this JavaFx thread still remain open... and I really don't want to force exit with System.exit() because if something is blocked I may want to know/wait (ALSO I don't want to execute everything as an JavaFx application (as JavaFx components are less than 1% of my main application)
the code is very simple and googling around I've found only to use
Platform.exit();
which doesn't seems to work, I've also tried playing with Platform parameters like
Platform.setImplicitExit(false);
here is my test application which you can run :
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.geometry.Pos;
import javafx.scene.layout.VBox;
public class SOTestFX {
public static void main(String[] args) {
SOTestFX t = new SOTestFX();
t.runFxThread();
}
public void runFxThread(){
//Application.launch(args);
final JFXPanel jfxPanel = new JFXPanel();
Platform.runLater(new Runnable() {
#Override
public void run() {
System.err.println("CREATING IMAGE");
simpleFXoperations();
System.err.println("NOW CALL EXIT");
System.err.println("JAVA FX THREAD SHOULD BE EXITED NOW");
Platform.exit();
}
});
try {
Thread.sleep(3000); // just wait a bit if something should happen, let it happen..
} catch (InterruptedException e) {
e.printStackTrace();
}
//jfxPanel.removeNotify(); // return -> java.lang.NullPointerException
//Platform.exit(); // -> does nothing
System.err.println("i will never die!");
}
public void simpleFXoperations(){
VBox vbox1 = new VBox();
vbox1.setAlignment(Pos.BOTTOM_CENTER);
vbox1.setStyle("-fx-border-style: solid;"
+ "-fx-border-width: 1;"
+ "-fx-border-color: white");
System.err.println("simpleFXoperations() _DONE");
}
}
and this is the thread which never close
"Attach Listener" - Thread t#17 java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"JavaFX Application Thread" - Thread t#13 java.lang.Thread.State:
RUNNABLE at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native
Method) at
com.sun.glass.ui.gtk.GtkApplication$3$1.run(GtkApplication.java:82)
at java.lang.Thread.run(Thread.java:722)
Locked ownable synchronizers:
- None
Update: I'm using latest Oracle JDK 7u17 64bit on Linux Fedora 16 64bit.
Fix:
I was able to fix this problem by calling com.sun.javafx.application.PlatformImpl.tkExit() immediately before Platform.exit(). I don't really understand the JavaFX source that well, but it seems to be working; YMMV.
Update: Doing this in Java 8 will produce a warning, you can just turn the warning off with #SuppressWarnings("restriction"). It shouldn't be a problem.
Explanation:
I figured this out by digging through the source code; JFXPanel has this little snippet (this is from JavaFX 2.2.25)
finishListener = new PlatformImpl.FinishListener() {
public void idle(boolean paramAnonymousBoolean) {
if (!JFXPanel.firstPanelShown) {
return;
}
PlatformImpl.removeListener(JFXPanel.finishListener);
JFXPanel.access$102(null);
if (paramAnonymousBoolean)
Platform.exit();
}
public void exitCalled()
{
}
The problem is, if you are using only a little bit of JavaFX in your application, then the idle(boolean) method never does anything (because firstPanelShown == false), which prevents the listener from getting removed, which prevents the JavaFX Toolkit from shutting down... which means you have to shut it down manually.
Your main function does not belong to the JavaFx Application object and i think that your program never eneter application thread loop.
It seems you should do:
public class SOTestFX extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
// Do stuff here to show your stage or whatever you want;
// This will be called on the JavaFX thread
}
}
That's a slippery situation, as (to my understanding) the purpose of the JavaFX thread is to take advantage of various hardware pipelines transparently. Might I suggest placing your JavaFX requests in a separate, referenced, project; and keep everything else, including your main method, in another? That's always worked for me.
Basically, business logic and model go in one project, and view and control (generally JavaFX-based) go in the other. This allows for independent termination of the JavaFX thread. Hopefully that is applicable to what you are trying to do.
I tried a lot of things on this as none of the above answers worked for me.
Best thing for me was to just shutdown the whole JVM using
System.exit(1);
as my whole Application is just that one JavaFX application and therefor can be shut down, when closing the Stage.
The 1 in my case is just a random int.

Categories

Resources