I have implemented a programm in javafx which dynamically generates an input mask and generates a Word-document after a button click on that mask.
I define in an db-table which input fields are available in this mask.
Now I'm adding support for custom procedures which are executed on specific states of my program (onFocusLost of an field,onChange,...)
Wich works perfect.
Now I'm stuck at the onGenerate execution.
When I render the mask, I hold a List of Runnables to store my actions which should be executed on generation (At the render time i know which action should be executed. At Generation time i would have to read all the data in again. So I thought I save the action with FunctionalInterface. And I need no inputParameter and no ReturnValue ... so i ended up with Runnable)
TextField tf = ...;
String s = ...;
actionsBeforeGenerate.add(() -> {
tf.setText(s);
});
So now, if I press the generate button, I do the following:
private void startGenerate(){
//main.getActionsBeforeGenerate() == List<Runnable>
main.getActionsBeforeGenerate().forEach(action -> action.run());
generateWordDocument();
}
The text is set to the node correctly, BUT after the document is generated.
How can I change the textField BEFORE my generationLogic starts?
If you need more information, don't hesitate to ask for it.
EDIT:
I think I've found the solution for my problem:
private void startGenerate(){
Task<Boolean> task = new Task<Boolean>() {
#Override
public Boolean call() throws Exception {
main.getActionsBeforeGenerate().forEach(action -> action.run());
....
generateWordDocument();
....
return Boolean.TRUE;
}
};
Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();
}
Now I have the new values textField values available in generateWordDocument()
Related
I was looking at this question JavaFX show dialogue after thread task is completed, but my question is kind of the opposite. What is the best way to thread off after a filechooser or alert where you need some data back from the user?
Here's what I have now:
Platform.runLater(()->{
File file = fileChooser.showOpenDialog(root.getScene().getWindow());
if(file == null) {
return;
}
executorService.execute(()->{
//more code here which uses file
});
});
where executorService is an ExecutorService that was made earlier. I suppose I could just as easily use a Task or a Thread or anything else, but how it's threaded off doesn't matter, just that it's something that takes a while that I don't want to have happen on the Application thread because it would lock up the UI.
I know this isn't an mvce, but I hope it demonstrates the problem I'm having with threads inside Platform.runLater calls.
Here's an extreme example of how convoluted this kind of thing gets
#FXML
public void copyFiles(ActionEvent event){
//this method is on the application thread because a button or something started it
// so we thread off here
executorService.execute(()->{
// do some stuff
// ...
// get location to copy to from user
// must happen on the application thread!
Platform.runLater(()->{
File file = fileChooser.showOpenDialog(root.getScene().getWindow());
if(file == null) {
return;
}
executorService.execute(()->{
// more code here which uses file
// ...
// oh wait, some files have the same names!
// we need a user's confirmation before proceeding
Platform.runLater(()->{
Alert alert = new Alert(AlertType.CONFIRMATION, "Do you want to overwrite files with the same names?", ButtonType.OK, ButtonType.CANCEL);
Optional<ButtonType> choice = alert.showAndWait();
if(choice.isPresent && choice.get == ButtonType.OK){
// do something, but not on the application thread
executorService.execute(()->{
// do the last of the copying
// ...
});
}
});
});
});
});
}
If you need to do something on the UI thread that returns a result, create a FutureTask, submit it the UI thread, and then on the background thread wait for it to complete. This allows you to "flatten" the code.
You can also abstract Platform.runLater(...) as an Executor (after all, it is just something that executes Runnables), which can make it (perhaps) slightly cleaner.
By dividing up into smaller methods (and generally just using other standard programming techniques), you can make the code pretty clean.
Here's the basic idea (you'll need to add exception handling, or create a Callable (which can throw an exception) instead of a Runnable):
#FXML
public void copyFiles(ActionEvent event){
Executor uiExec = Platform::runLater ;
//this method is on the application thread because a button or something started it
// so we thread off here
Callable<Void> backgroundTask = () -> {
doFirstTimeConsumingThing();
FutureTask<File> getUserFile = new FutureTask<>(this::getUserFile) ;
uiExec.execute(getUserFile);
File file = getUserFile.get();
if (file == null) return null ;
doAnotherTimeConsumingThing(file);
FutureTask<Boolean> getUserConfirmation = new FutureTask<>(this::showConfirmation);
uiExec.execute(getUserConfirmation);
if (! getUserConfirmation.get()) return null ;
doMoreTimeConsumingStuff();
// etc...
return null ;
};
executorService.execute(backgroundTask);
}
private File getUserFile() {
return fileChooser.showOpenDialog(root.getScene().getWindow());
}
private Boolean getUserConfirmation() {
Alert alert = new Alert(AlertType.CONFIRMATION, "Do you want to overwrite files with the same names?", ButtonType.OK, ButtonType.CANCEL);
return alert.showAndWait()
.filter(ButtonType.OK::equals)
.isPresent();
}
private void doFirstTimeConsumingThing() {
// ...
}
private void doAnotherTimeConsumingThing(File file) {
// ....
}
private void doMoreTimeConsumingStuff() {
// ...
}
It seems your issue is needing information in the middle of a background task that can only be retrieved while on the JavaFX Application thread. The answer given by James_D works perfectly for this using FutureTask. I'd like to offer an alternative: CompletableFuture (added in Java 8).
public void copyFiles(ActionEvent event) {
executorService.execute(() -> {
// This uses CompletableFuture.supplyAsync(Supplier, Executor)
// need file from user
File file = CompletableFuture.supplyAsync(() -> {
// show FileChooser dialog and return result
}, Platform::runLater).join(); // runs on FX thread and waits for result
if (file == null) {
return;
}
// do some stuff
// ask for confirmation
boolean confirmed = CompletableFuture.supplyAsync(() -> {
// show alert and return result
}, Platform::runLater).join(); // again, runs on FX thread and waits for result
if (confirmed) {
// do more stuff
}
});
}
Both FutureTask and CompletableFuture will work for you. I prefer CompletableFuture because it it provides more options (if needed) and the join() method doesn't throw checked exceptions like get() does. However, CompletableFuture is a Future (just like FutureTask) and so you can still use get() with a CompletableFuture.
I am using JavaFx for creating a Java Standalone Application.
I have seen some examples but I am not able to understand how to use the javaFX Task in my code scenario.
This is the Controller function which I am calling for Button onAction which I have set from SceneBuilder -->
public class MainScreenController {
#FXML
private JFXButton btnSelectImg;
#FXML
private ImageView imageViewObj;
#FXML
private ProgressBar progressBarObj;
//..
//..
#FXML
private void onFileSelectButtonClick() {
//Some Operations are carried out
//..
//Then I want to set Image in ImageView
imageViewObj.setImage(myImage);
// Some Code Here
//..
// Set Progress
progressBarObj.setProgress(0.1);
// Some Code Here
//..
// Set Progress
progressBarObj.setProgress(0.2);
//...
//...
// Maybe change some other Controls
//..........
}
//..
//..
}
Now here I am updating multiple controls in the same function gradually as the code progresses step by step but it gets updated at last when execution is done.
I want to update the controls while execution as shown in the code.
This is a likely a duplicate of bits of other questions:
JavaFx: Update UI label asynchronously with messages while application different methods execution
JavaFx ProgressBar doesnt update
Platform.runLater and Task in JavaFX
Usage of JavaFX Platform.runLater and access to UI from a different thread
And perhaps some other questions.
As an overall approach, you define a Task, then within the execution body of the Task, you make use of Platform.runLater(), updateProgress() and other mechanisms to achieve what you need. See the related question for further explanations of these mechanisms.
final ImageView imageViewObj = new ImageView();
Task<Void> task = new Task<Void>() {
#Override protected Void call() throws Exception {
//Some Operations are carried out
//..
//Then I want to set Image in ImageView
// use Platform.runLater()
Platform.runLater(() -> imageViewObj.setImage(myImage));
// Some Code Here
//..
// Set Progress
updateProgress(0.1, 1);
// Some Code Here
//..
// Set Progress
updateProgress(0.2, 1);
int variable = 2;
final int immutable = variable;
// Maybe change some other Controls
// run whatever block that updates the controls within a Platform.runLater block.
Platform.runLater(() -> {
// execute the control update logic here...
// be careful of updating control state based upon mutable data in the task thread.
// instead only use immutable data within the runLater block (avoids race conditions).
});
variable++;
// some more logic related to the changing variable.
return null;
}
};
ProgressBar updProg = new ProgressBar();
updProg.progressProperty().bind(task.progressProperty());
Thread thread = new Thread(task, "my-important-stuff-thread");
thread.setDaemon(true);
thread.start();
I have an interface method which is supposed to return a Future object.
Future<Result> doSomething()
The implementation of this method shows some ui (javafx).
One of the ui elements has a listener, that needs to be called in order to receive the actual result, I need.
How do I achieve this?
Is there a better solution?
Here an example action I need to wait for:
// this is some framework method I cannot change
#Override
public Data execute(Data data) {
Future<Data> dataFuture = handler.doSomething(data);
// this should basically wait until the user clicked a button
return dataFuture.get();
}
// handler implementation
public Future<Data> doSomething(Data data) {
// the question is how to implement this part, to be able to
// return a future object
Button button = new Button("Wait until click");
// create thread that waits for the button click ?!????
// modify incoming data object when the button was clicked
// somehow create the Future object that's bound to the button click
return future;
}
This is what I want to achieve:
my method doSomething shows a new scene(ui) with a button on it
and returns immedeately the future object
future.get() waits until the user pressed the button
limitations: it has to be done with no extra library and on >=Java7
Use a javafx.concurrent.Task. It derives from FutureTask. There are extensive examples in the linked javadoc on Task usage.
Oracle also provide a tutorial which discusses Task usage:
Concurrency in JavaFX
I think this is what you want, but I may have understood the question, if so, please edit the question a bit to clarify requirements (perhaps with an mcve). The bit that makes me a little unsure is the part in your title "waiting for ui event?", I'm not quite sure what that means in this context.
This is a solution I was searching for. It's not very nice, since the Thread.sleep doesn't convince me.
but now you propably get an idea of what I want to achieve
// make sure this is not called on the ui thread
public Future<Data> doSomething(Data data) {
WaitingFuture future = new WaitingFuture(data);
Platform.runLater(() -> {
Button button = new Button("Wait until click");
button.setOnAction(future);
// show button on ui...
});
favouriteExecutorService.submit(future);
return future;
}
static class WaitingFuture extends Task<Data> implements EventHandler<ActionEvent> {
private Data data;
WaitingFuture(Data originalData) {
this.data = originalData;
}
private Data waitingData;
#Override
public void handle(ActionEvent event) {
waitingData = data.modify();
}
#Override
protected Data call() throws Exception {
while (waitingData == null) {
Thread.sleep(100);
}
return waitingData;
}
}
I posted a question yesterday about preventing the UI from freezing when using a scheduledexecutorservice here What should I do in order to prevent the UI from freezing(scheduledexecutorservice) and most people suggested using SwingWorker instead of scheduledexecutorservice. However, I've been stuck since then trying to figure out how a SwingWorker thread would work in my case.
I have the following pseudocode:
createGraph(){
if(rule1)
n = new Node()
graph.add(n)
animateGraph()
createGraph()
if(rule2)
...
I have a recursive algorithm which creates a graph based on certain rules and I want to update the UI when a rule is matched and a new vertex/edge is added to the graph. My question is how can I display the graph whenever a new node/edge is added to it? This should happen in the animateGraph() method and when it hits this method, it should update the actual UI, preferably wait for 1500ms and do that until the whole graph is built.
I tried creating a SwingWorker thread. In this case it doesn't show the intermediate steps of the graph creation but only the final graph. First, it executes all calls to doInBackground() and then it goes to done().
NB: I create a new SwingWorker thread every time a new vertex/edge is created as I read that doInBackground() is only called once.
private void animateGraph() {
swingWorker = createRunnable();
swingWorker.execute();
}
private void displayGraph() {
JPanel.add(graph);
}
private SwingWorker<Object, Object> createRunnable() {
swingWorker = new SwingWorker<Object, Object>() {
#Override
protected Void doInBackground() throws Exception {
System.out.println("Start sleeping.. " + new Date());
Thread.sleep(1500);
publish(new NodeTuple(new Node("A"), new Node("B")));
return null;
}
protected void process(List<NodeTuple> chunks) {
System.out.println("In process.. " + new Date());
NodeTuple nodeTuple = chunks.get(chunks.size() - 1);
graph.addVertex(nodeTuple.source);
graph.addVertex(nodeTuple.target);
checkIfToAddEdge(nodeTuple.source, nodeTuple.target);
createDiagram();
}
}
};
return swingWorker;
}
Edit: I updated doInBackground() and process() methods. However, I still don't get what I really want. No intermediate steps are shown and only the final graph is displayed.
You should probably use the publish/process API of the SwingWorker (see the second example of the SwingWorker API doc for code).
This will allow you create nodes recursively and off the EDT, then publish new nodes matching your rule, before finally processing these nodes on the EDT for display or animation.
Adding animation will need it's own thread, and I suggest you add that as a separate task, but at least you should be able to see new nodes showing up as they are added to the graph.
To see the intermediate steps, you have to publish() each new Node as it's created and process() it on the event dispatch thread, like they show in Tasks that Have Interim Results.
class FlipTask extends SwingWorker<List<Node>, Node> {
#Override
protected List<Node> doInBackground() {
…
publish(new (Node);
…
}
protected void process(List<Node> list) {
// add each new Node to the view
}
}
I have search as you type functionality although it searches very fast and I can't notice it even with no multithreading I still want to know how would I use multithreading on this
search.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s2) {
manager.searchString(s2);
listView.getItems().setAll(manager.getList());
}
});
So basically there is a TextField that when its text is changed I go and call a search method in object manager which puts its search result in an array when it finishes.
Then the ListView should update its data to this new array when it finishes.
How can I make the search on one thread and when it finishes it update the list data?!
I believe I can't just call the list function from other thread because GUI stuff should be called from only one thread.
To do this efficiently in a different thread is not as simple as it sounds.
You don't want to create and execute a new thread every time a key is pressed because:
There is system overhead for thread creation which would make that an extremely intensive process
There's no guarantee that the threads will execute and complete in the order they are created, so you may get an earlier thread finishing after a subsequent one and consequentially updating the list with invalid entries.
You could use a single-thread executor service (which keeps one thread alive and uses it to execute Runnables passed into it in order), which would be more efficient, but you'd need to remember to shut it down when your text field is destroyed (if you do ever destroy your text field). Something along these lines:
// first of all, at the class level (assuming listView and manager are both class-level variables, preferably final ones, too):
// An INNER class implementing Runnable which will carry out the searching
private class Searcher implements Runnable {
private volatile boolean cancelled = false;
private final String searchTerm;
Searcher(String searchTerm) {
this.searchTerm = searchTerm;
}
public void cancel() {
cancelled = true;
}
#Override
public void run() {
// remember that there's no guarantee that this will execute before the NEXT keypress, so we add a check to ensure that we still want to perform the search when it gets executed:
if (!cancelled) {
manager.searchString(searchTerm);
Platform.runLater(listViewUpdater); // listViewUpdater is defined below
}
}
}
// a Runnable to actually update the GUI after a seach has been performed
private Runnable listViewUpdater = new Runnable(){
#Override
public void run() {
listView.getItems().setAll(manager.getList());
}
}
private ExecutorService executor = Executors.newSingleThreadExecutor();
private Searcher lastSearcher = null;
// ... then, in the method which sets up the GUI
search.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s2) {
if (lastSearcher != null) {
lastSearcher.cancel(); // prevents lastSearcher from running if it hasn't done so already
}
lastSearcher = new Searcher(s2);
executor.submit(lastSearcher);
}
});
The downside is you are creating a new object every time the value changes, but that isn't nearly as bad as creating a new Thread every time.