Re-implement JavaFX showAndWait [closed] - multithreading

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I want to achieve the functionality of Stage.showAndWait() without using the method itself.
I have an application and I need a way of displaying something within the same stage and block the thread displaying the content until a button is pressed.
The thread displaying the content naturally needs to be tha JavaFX application thread - which of course won't handle the buttons as long as it is blocked.
Stage.showAndWait describes its inner workings as "This method temporarily blocks processing of the current event, and starts a nested event loop to handle other events." I see that the method calls "Toolkit.getToolkit().enterNestedEventLoop(this)", which is pretty implementation specific. Are there any other options? Is functionality like this exposed anywhere in the API?
Edit:
Since my question was misleading, I try to rephrase it more to the point from my current perspective:
Is there a public API for Toolkit.getToolkit().enterNestedEventLoop() and Toolkit.getToolkit().exitNestedEventLoop() ?

For my rephrased question:
Is there a public API for Toolkit.getToolkit().enterNestedEventLoop() and Toolkit.getToolkit().exitNestedEventLoop() ?
Since then the API has been made public in:
javafx.application.Platform.enterNestedEventLoop()

It isn't really clear what you are trying to do, but it sounds like you have some long running process that is building up some kind of data, and then you want the user to control how that built up data is delivered to the screen. In that case, then you need to run a background task to build the data, transfer that data to some element that is available to the FXAT, and then use the action event of a button to move the data onto the screen. Something like this:
public class LongTask extends Application {
StringProperty results = new SimpleStringProperty("");
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
TextArea textArea = new TextArea();
BorderPane root = new BorderPane();
root.setCenter(textArea);
Button button = new Button("More Data");
root.setBottom(button);
button.setOnAction(evt -> textArea.setText(results.get()));
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
Task<Void> sleeper = new Task<Void>() {
#Override
protected Void call() throws Exception {
for (int iteration = 0; iteration < 1000; iteration++) {
try {
Thread.sleep(5000);
int i = iteration;
Platform.runLater(() -> results.set(results.get() + "\nIteration " + i));
} catch (InterruptedException e) {
}
}
return null;
}
};
new Thread(sleeper).start();
}
}
Technically, you don't need to make "results" a property, nor do you need to update it through Platform.runlater(). Using Platform.runlater() guarantees that you won't have concurrency issues with results. Also, if you bind "results" to anything, then you'll need to use Platform.runlater() to modify it.

Related

Using Thread.sleep to get waiting effect in JavaFX [duplicate]

This question already has answers here:
JavaFX periodic background task
(6 answers)
Closed 5 years ago.
I want to achieve something like this: user press the login button and then label shows:
"Connecting."
0.5 sec time interval
"Connecting.."
0.5 sec time interval
"Connecting..."
etc
Just a visual effect that indicates something is actually going on "under the hood".
All I managed to get wasn't quite what I was expecting. I click the button, wait 1.5 sec and then I got "Connecting...", missing 2 previous steps.
First, my Status class
public class Status {
private static StringProperty status = new SimpleStringProperty();
public static void setStatus(String newStatus) {
status.setValue(newStatus);
}
public static String getStatus() {
return status.getValue();
}
public static StringProperty get() {
return status;
}
}
and my LoginView class
public class LoginView extends Application {
private Button loginButton = new Button("Log in");
private Label statusLabel;
private void createLabels() {
statusLabel = new Label(Status.getStatus());
statusLabel.textProperty().bind(Status.get());
}
}
private void createButtons() {
loginButton.setOnAction(e -> {
try {
Status.setStatus("Connecting.");
Thread.sleep(500);
Status.setStatus("Connecting..");
Thread.sleep(500);
Status.setStatus("Connecting...");
Thread.sleep(500);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
});
}
Run a Task from a different thread. Task allows you to update it's message property on the JavaFX application thread that should be used to update the GUI and must not be blocked by long-running tasks, since it's responsible for rendering:
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws InterruptedException {
updateMessage("Connecting.");
Thread.sleep(500);
updateMessage("Connecting..");
Thread.sleep(500);
updateMessage("Connecting...");
Thread.sleep(500);
return null;
}
};
// bind status to task's message
Status.get().bind(task.messageProperty());
// run task on different thread
new Thread(task).start();
You should do animations with the Timeline API. Have a look here:
https://docs.oracle.com/javase/8/javafx/api/javafx/animation/Timeline.html
Basically you just define KeyFrames at 0.5 seconds distance and set the value of the text to add a another dot. You can also make it repeat indefinitely until the connection is established to get cyclic animation.
Another way is to make a SequentialTransition which will have two PauseTransitions of 0.5 seconds.
BTW in your code you pause the main UI thread and that is why you can’t see the animation.

Having trouble with AsyncTask using a recursive method

I've been reading about AsyncTasks and Hanlders and Loopers but I still can't figure out where I'm going wrong in my code. I'm trying to run code that will look over a Tic Tac Toe grid and determine the best move for the computer. I want this code to run in the background 'cause it can take some time and then I can update the UI level with a textbox that says something like "I'm Thinking". I've tried this a bunch of different ways, none with success.
private class PostTask extends AsyncTask<String, Integer, String> {
private Board _b;
private Welcome.Player _opp;
private int _depth;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected void SetVars(Board b, Player p, int depth){
_b = b;
_opp = p;
_depth = depth;
}
#Override
protected String doInBackground(String... params) {
Looper.prepare();
try{
_bestMove = _b.GetBestMove(_opp,_depth);
}
catch(Exception err){
_bestMove = -1;
}
return "All done";
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(_bestMove == -1){
TextView tv = (TextView) findViewById(R.id.tv_Score);
tv.setText("Had and error, couldn't make a move.");
}
FollowUpComputerMove(this);
}
The above code will work for exactly 5 moves and then it crashes. When I watch in the debugger I see new theads being created named Thread<#> AsyncTask #1. Once I get to five of those AsyncTasks it goes back to try and grab the first AsyncTask and crashes. When it crashes I'm shown the ThreadPoolExecutor.class file.
I've also read that I shouldn't be using both the AsyncTask and the Looper objects together so I've tried taking the Loooper.prepare() statement out, but then my AsyncTask fails immediately with the error message:
Can't create handler inside thread that has not called Looper.prepare() - AsyncTask inside a dialog
I've read repeatedly that you shouldn't be trying to update the UI from an AsyncTask and that often the above error is because of that, but GetBestMove isn't updating the UI thread. When I trace through to see where the error comes, it fails when calling a constructor saying it can't find the class.
Can anyone point me in the right direction? My end goal is to use one main thread and only one background thread, and just keep re-using the background thread whenever the computer needs to make a move. I know that the recursive method GetBestMove works when I run this program in a single-thread manner. But the screen freezes for too long on some moves as the method is being run. Thank you so much.
-NifflerX
Apologies for answering my own question, but the issue I was facing had nothing to do with recursion. The class I was calling was extending the class Activity, and while trying to call that from an AsyncTask the program was erroring out. When I removed the extends Activity from the class definition it started working again. Sorry for the post.
-NifflerX

Javafx 2 Notification Refresh

I have a requirement in JavaFX 2 to display the notifications on the header. These notifications are populated in the database through an external system.
When a new notification is inserted in the database, my JavaFX application should listen to the same and refresh the header.
One solution I can think about is to implement a timeline that triggers the code to retrieve the latest notification status once every fixed time period, may be once every 2 mins.
Other than this, is there any other way to achieve this? Any hints on this would be highly appreciated.
You can create a new Task that would be listening (or checking) for changes in your database. This Task would be running in a different Thread as not to block your UI. Once a change occurs, it can then update your UI.
Your code could look like this :
//... initialize your variables.
task = new DatabaseWatcher();
executor = Executors.newSingleThreadExecutor();
executor.execute(task);
And your DatabaseWatcher :
public class DatabaseWatcher extends Task<Object> {
public DatabaseWatcher() {
//initialize here
}
#Override
protected Object call() throws Exception {
//Get data from database
//if new update :
updateUI();
return null;
}
private void updateUI() {
Platform.runLater(new Runnable() {
#Override
public void run() {
//Set your new values in your UI
//Call the method in your UI to update values.
}
});
}
}
This should get you started on the right path.
See Also
Multiple FXML with Controllers, share object, more specifically this answer
javafx, update ui from another thread
Concurrency in JavaFX

How to close all stages when the primary stage is closed?

I have an application where I call the following code when an exception occurs- that is, it is located within the "catch" of a "try/catch". It merely creates a "popup"-like window which tells the user to enter an int instead.
Stage dialogStage = new Stage();
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.setScene(new Scene(VBoxBuilder.create().
children(new Text("Please enter an integer."), new Button("Ok.")).
alignment(Pos.CENTER).padding(new Insets(5)).build()));
dialogStage.show();
The only problem is that the stage lingers even if the primary stage (that is the parameter in the public void start(Stage primaryStage)) is closed.
What have I tried?:
I made the dialogstage visible in the whole class by defining it as a class variable. Then I implemented the following code:
primaryStage.setOnCloseRequest((new EventHandler<WindowEvent>(){
#Override
public void handle(WindowEvent arg0) {
arg0.consume();
try
{
dialogStage.close();
}
catch(Exception ex)
{
System.out.print(ex.getMessage()+"\r\n");
}
}
}));
}
This "works" in that the dialogstage is closed when a user tries to exit the main application, however, it does not actually do what I intended: when you try to close the primary stage only the dialogstage is closed.
It is also an aesthetically displeasing solution as I don't want the whole class to know about the stupid dialog box which is only located in one try/catch and might never be used.
I'd like to know if there is a simple solution that tells the dialogstage to close when the primary stage does and where I don't have to write much code outside of my try/catch.
On the event OnCloseRequest on your main stage, perform Platform.exit (docs.oracle.com/javafx/2/api/javafx/application/Platform.html)

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.

Resources