JavaFX Can i repaint a Stage? - javafx-2

After you put some values in the programm over the keyboard, the stage started, But at the same time i would like to have the stage is open, user can put some values again and the stage restart.
Is that possible?
I would like to do something like this:
primaryStage.setScene(scene);
primaryStage.show();
javafx.application.Platform.runLater(new Runnable() {
public void run() {
if (TastaturEingabe.readBoolean("Möchten Sie ein neues Diagramm zeichnen?")) {
// Input through keyboard
readInputJahrgang(vintage, FIRST_PROMPT);
readInputLager(vintage, FIRST_PROMPT);
primaryStage.hide();
} else {
primaryStage.close();
}
return;
}
});

This is a wrong design of interacting between user and application.
javafx.application.Platform.runLater(new Runnable() {
public void run() {
will be run on JFX thread, and while you are talking with a user in a command line, UI will be frozen.
You can talk to a user via comandline in a separate thread, which can use runLater() calls to inform JFX, about new user input.
So, you can create a separate thread in a start method, and put
readInputJahrgang(vintage, FIRST_PROMPT);
readInputLager(vintage, FIRST_PROMPT);
calls in its runnable.
When user input new info, which is needed to redraw a UI, call runLater().
In common case, you don't need to force JavaFX to redraw anything. It will do everything by itself

Related

I am running a javafx program and I am getting an IllegalStateException in a situation where I would expect usual Thread interference

tl:dr at the bottom. I am taking a Java course on Udemy and our instructor is demonstrating a situation where background threads can interfere with each other and crash the program. In this case pushing either of the two buttons initiates a method that starts a background Thread, waits, then updates a label. He explains it something along the lines as the threads overwriting each other causing the program to crash with an IllegalStateException. What I don't understand is Threads overwriting each other is not uncommon and just makes the program behave in ways not intended and doesn't usually completely crash the program.
In this case the threads are both trying to change the label to the same String.
Why is this throwing an IllegalStateException instead of just causing the usual interference? After all more than one thread trying to update an object doesn't necessarily crash the program.
tl:dr Why does more than one thread modifying a Label object throw an IllegalStateException in this case but in other multi-threaded programs you just get the usual thread interference? The method of interest is the onButtonClicked() method.
I have tried catching the IllegalStateException to see if I can call Thread.currentThread().getName() but the catch block(both of them actually) seem to get ignored.
public class Controller {
#FXML
private TextField nameField;
#FXML
private Button helloButton;
#FXML
private Button byeButton;
#FXML
private CheckBox ourCheckBox;
#FXML
private Label ourLabel;
#FXML
public void initialize() {
helloButton.setDisable(true);
byeButton.setDisable(true);
}
#FXML
public void onButtonClicked(ActionEvent event) {
if (event.getSource().equals(helloButton)) {
System.out.println("hello, " + nameField.getText());
} else if (event.getSource().equals(byeButton)) {
System.out.println("Bye, " + nameField.getText());
}
Runnable task = new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
ourLabel.setText("We did something");
} catch (InterruptedException e) {
System.out.println("Interuppted Exception " + e.getMessage());
} catch (IllegalStateException e) {
System.out.println("Illegal State Exception: " + e.getMessage() + " "
+ Thread.currentThread().getName());
}
}
};
new Thread(task).start();
if (ourCheckBox.isSelected()) {
nameField.clear();
byeButton.setDisable(true);
helloButton.setDisable(true);
}
}
#FXML
public void handleKeyReleased() {
String text = nameField.getText();
boolean disableButtons = text.isEmpty() || text.trim().isEmpty();
byeButton.setDisable(disableButtons);
helloButton.setDisable(disableButtons);
}
#FXML
public void handleChange() {
System.out.println("The checkbox is " +
(ourCheckBox.isSelected() ? "checked" : "not checked"));
}
}
Updating active scene graph elements (such as label text) in your own threads has the potential to cause a race condition (please read and understand the Software section of the link) in the internal state of the JavaFX system. The results of which are unpredictable and a corruption or ”crash” of the JavaFX system cannot be ruled out. Perhaps nothing bad will happen, but perhaps something bad will.
Some calls to JavaFX APIs will detect when potential race condition may occur (when they are being invoked by a thread which is not the JavaFX thread), and fail fast by throwing an IllegalStateException. Other JavaFX APIs may not bother to check the calling thread and may not throw an IllegalStateException, thus allowing the potential race condition to occur. Either way, the users calling code is wrong, it should not be trying to modify the active scene graph off of the JavaFX application thread.
JavaFX code which manipulates the active scene graph (elements or properties of elements currently being displayed in a rendered scene) is only ever expected to occur on a single thread (the JavaFX application thread). In that way a race condition cannot occur.
If you want to feedback information from another thread to the UI, then you can either use the Platform.runLater API, which will execute a piece of code at some time in the future on the JavaFX thread, or make use of utilities in the javafx.concurrent package.

Timers and javafx

I am trying to write a code that will make things appear on the screen at predetermined but irregular intervals using javafx. I tried to use a timer (java.util, not javax.swing) but it turns out you can't change anything in the application if you are working from a separate thread.(Like a Timer) Can anyone tell me how I could get a Timer to interact with the application if they are both separate threads?
You don't need java.util.Timer or java.util.concurrent.ScheduledExecutorService to schedule future actions on the JavaFX application thread. You can use JavaFX Timeline as a timer:
new Timeline(new KeyFrame(
Duration.millis(2500),
ae -> doSomething()))
.play();
Alternatively, you can use a convenience method from ReactFX:
FxTimer.runLater(
Duration.ofMillis(2500),
() -> doSomething());
Note that you don't need to wrap the action in Platform.runLater, because it is already executed on the JavaFX application thread.
berry120 answer works with java.util.Timer too so you can do
Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
public void run() {
Platform.runLater(new Runnable() {
public void run() {
label.update();
javafxcomponent.doSomething();
}
});
}
}, delay, period);
I used this and it works perfectly
If you touch any JavaFX component you must do so from the Platform thread (which is essentially the event dispatch thread for JavaFX.) You do this easily by calling Platform.runLater(). So, for instance, it's perfectly safe to do this:
new Thread() {
public void run() {
//Do some stuff in another thread
Platform.runLater(new Runnable() {
public void run() {
label.update();
javafxcomponent.doSomething();
}
});
}
}.start();

JavaFX working with threads and GUI

I have a problem while working with JavaFX and Threads. Basically I have two options: working with Tasks or Platform.runLater. As I understand Platform.runLater should be used for simple/short tasks, and Task for the longer ones. However, I cannot use any of them.
When I call Thread, it has to pop up a captcha dialog in a middle of task. While using Task, it ignores my request to show new dialog... It does not let me to create a new stage.
On the other hand, when I use Platform.runLater, it lets me show a dialog, however, the program's main window freezes until the pop up dialog is showed.
I need any kind of solution for this. If anyone knows how to deal with this or had some similar experience and found a solution I am looking forward to hearing from you!
As puce says, you have to use Task or Service for the things that you need to do in background. And Platform.runLater to do things in the JavaFX Application thread from the background thread.
You have to synchronize them, and one of the ways to do that is using the class CountDownLatch.
Here is an example:
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
//Background work
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//FX Stuff done here
}finally{
latch.countDown();
}
}
});
latch.await();
//Keep with the background work
return null;
}
};
}
};
service.start();
Use a Worker (Task, Service) from the JavaFX Application thread if you want to do something in the background.
http://docs.oracle.com/javafx/2/api/javafx/concurrent/package-summary.html
Use Platform.runLater from a background thread if you want to do something on the JavaFX Application thread.
http://docs.oracle.com/javafx/2/api/javafx/application/Platform.html#runLater%28java.lang.Runnable%29
It's too late to answer but for those who have the error, here is the solution XD
You can use one Thread.
Use the lambda expression for the runnable in the thread and the runlater.
Thread t = new Thread(() -> {
//Here write all actions that you want execute on background
Platform.runLater(() -> {
//Here the actions that use the gui where is finished the actions on background.
});
});
t.start();
You can user directly this code
Don't forget you can't send non-final variable in thread .
you can send final variable in thread
//final String me="ddddd";
new Thread(new Runnable() {
#Override
public void run() {
// me = me + "eee";
//...Your code....
}
}).start();
Use in
your code
try/catch

Creating a JavaFX Dialog Box

I am coding a javafx program and i need to create and use my own Stage based (Javafx.Stage) dialog box for showing messages and confirmations. I have written all the necessary code by now but i have a problem:
A dialog box must stop execution of rest of the code until a respond is given like "yes" or "no" or "retry". When i use my dialog box like "DialogBox.ShowMessage", a stage appears with message and buttons. But, as you may think, the rest of the code continues to execute. How can i get around this? When i create the stage, it must stop the other threads or the thread that it depends on. I have searched through internet and here, but i can not find exact solution. One idea is using "javafx.event.EventDispatcher" or "javafx.event.EventDispatchChain" but i couldn't figure out how to use them. And another idea is using "java.awt.EventQueue". And here is somthing that can help: I have a control of stage show and hide events and showing or hiding eventhandlers. I think som sort of thread queue can be used in one of these spesific sections.
I hope i clarified the situation enough. Briefly, ı need to manage threads while using another stage with my own code.
Thank you.
About execution suspending there is a Jira issue for it http://javafx-jira.kenai.com/browse/RT-19783.
As a workaround, I have no idea how to use EventDispatcher and EventDispatchChain to overcome this problem but you can send the EventHandlers as parameter. For instance,
public static void ShowMessage(final EventHandler<ActionEvent> okAction, final EventHandler<ActionEvent> cancelAction){
// Define and add buttons to the "view" and show message
btnOk.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
okAction.handle(null);
}
});
btnCancel.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
cancelAction.handle(null);
}
});
}
and use it as,
DialogBox.ShowMessage(
new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent arg0) {
// Do stuff when "ok" clicked.
},
new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent arg0) {
// Do stuff when "cancel" clicked.
});
I agree with this is a kind of "winding" way however.
Siteye hoş geldin ve kolay gelsin.

Thread Invalid Access Error in SWT

Could you let me know the reason for this error in SWT
"org.eclipse.swt.SWTException" Invalid Thread access ?
And How to fix such errors.
It happens when you try to act upon an interface item from a thread that's not the UI thread.
To run a code on the UI thread you have to use a Runnable and ask the display thread to run it. This way:
Display.getDefault().syncExec( new Runnable() {
#Override
public void run() {
// Do your job here
}
} );
As stated by the syncExec method javadoc,
the thread which calls this method is suspended until the runnable completes.
Also, you might check the asyncExec method.
In SWT you can access GUI resources only from the display thread. For example when setting the text in a org.eclipse.swt.widgets.Text control you must already be in the display thread or call
final Text text = ...;
Display.getCurrent().syncExec(new Runnable() {
#Override
public void run() {
text.setText("test");
}
});

Resources