I'm making a program which sends some data to the Matlab and receives output from matlab. To do that, I used matlabcontrol library.
Problem
After I click Java FX application button to submit data, matlabcontrol opens Matlab for further calculations. But when java opens the matlab, Java FX application stuck with wait cursor.Then starts to work again after Matlab finishes the process of calculation.
What I did
public void runner()
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
firstFunc();
}
});
Platform.runLater(new Runnable()
{
#Override
public void run()
{
secondFunc();
}
});
}
public void firstFunc()
{
// This function controls UI while Matlab does it's calculations
double progress = 0.2;
progressLabel.setText(progress*100+"% Completed");
progressBar.setProgress(progress);
}
public void secondFunc()
{
// This method creates matlab connection and handle matlab
firstClass mainFunc = new firstClass(pathSelected);
mainFunc.func();
}
So I used Platform runLater to run two methods separately. But still my program stuck with wait cursor when Matlab starts to functioning.
I also used threads to run these functions in parallel. But had the same issue. How can I correct this. Any help?
Update
As described in this question, I did use service and task with countdownlatch. But still didn't get what I wanted. In there,
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
firstFunc();
}finally{
latch.countDown();
}
}
});
latch.await();
//Keep with the background work
// I added matlab calling function here.
secondFunc();
return null;
}
};
}
};
service.start();
latch await and let background work to carry on. But in my case, my FX application shows a progress bar. So it should always update while background task happens. In here, it finishes FX task and moves to background task. I didn't get what I wanted. please help.
I had to use Service, Task and CountDownLatch to accomplish this task as I mentioned in Question Update part.
Also, I had to run another task inside the firstFunc, where I did update the progress. Like in this answer.
Related
basically, I have this code which was initially working with console i/o now I have to connect it to UI. It may be completely wrong, I've tried multiple things although it still ends up with freezing the GUI.
I've tried to redirect console I/O to GUI scrollpane, but the GUI freezes anyway. Probably it has to do something with threads, but I have limited knowledge on it so I need the deeper explanation how to implement it in this current situation.
This is the button on GUI class containing the method that needs to change this GUI.
public class GUI {
...
btnNext.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
controller.startTest(index, idUser);
}
});
}
This is the method startTest from another class which contains instance of Question class.
public int startTest() {
for (int i = 0; i < this.numberofQuestions; i++) {
Question qt = this.q[i];
qt.askQuestion(); <--- This needs to change Label in GUI
if(!qt.userAnswer()) <--- This needs to get string from TextField
decreaseScore(1);
}
return actScore();
}
askQuestion method:
public void askQuestion() {
System.out.println(getQuestion());
/* I've tried to change staticaly declared frame in GUI from there */
}
userAnswer method:
public boolean userAnswer() {
#SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
if( Objects.equals(getAnswer(),userInput) ) {
System.out.println("Correct");
return true;
}
System.out.println("False");
return false;
}
Thanks for help.
You're correct in thinking that it related to threads.
When you try executing code that will take a long time to process (eg. downloading a large file) in the swing thread, the swing thread will pause to complete execution and cause the GUI to freeze. This is solved by executing the long running code in a separate thread.
As Sergiy Medvynskyy pointed out in his comment, you need to implement the long running code in the SwingWorker class.
A good way to implement it would be this:
public class TestWorker extends SwingWorker<Integer, String> {
#Override
protected Integer doInBackground() throws Exception {
//This is where you execute the long running
//code
controller.startTest(index, idUser);
publish("Finish");
}
#Override
protected void process(List<String> chunks) {
//Called when the task has finished executing.
//This is where you can update your GUI when
//the task is complete or when you want to
//notify the user of a change.
}
}
Use TestWorker.execute() to start the worker.
This website provides a good example on how to use
the SwingWorker class.
As other answers pointed out, doing heavy work on the GUI thread will freeze the GUI. You can use a SwingWorker for that, but in many cases a simple Thread does the job:
Thread t = new Thread(){
#Override
public void run(){
// do stuff
}
};
t.start();
Or if you use Java 8+:
Thread t = new Thread(() -> {
// do stuff
});
t.start();
For JavaFX UI node, if I register an event handler:
final MenuItem buyItem = new MenuItem("Buy");
buyItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
String symbol = row.getItem().getSymbol();
String instrumentID = row.getItem().getInstrumentID();
.....
}
);
I can assume code inside handle() will always be executed in JavaFX application Thread, so there is no need to wrap them inside Platform. runLater.
But when I work with javafx.concurrent.Task:
import javafx.concurrent.Task;
public class BuyTask extends Task<Map<String, Object>> {
......
}
BuyTask buyTask = new BuyTask(this.api, params);
Thread buyThread = new Thread(buyTask);
buyThread.start();
buyTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(final WorkerStateEvent workerStateEvent) {
Map<String, Object> result = (Map) workerStateEvent.getSource().getValue();
.......
Platform.runLater(new Runnable() {
#Override public void run() {
portfolioService.restart();
}
});
}
}
In which thread is the task's event handler executed in? As I need to do perform restart on a javafx.concurrent.ScheduledService -> portfolioService.restart() which mentioned must be done in JavaFX Application Thread, I wrap it inside Platform.runLater.
But is it required? Will this task event handler always being executed in JavaFX Application Thread as well? Thanks!
The JavaFX documentation for Task has the answer:
Because the Task is designed for use with JavaFX GUI applications, it ensures that every change to its public properties, as well as change notifications for state, errors, and for event handlers, all occur on the main JavaFX application thread.
So - no, there is no need to wrap the call with Platform.runLater.
I'm trying to animate something when a task is completed. The problem here is I get this error message:
android.util.AndroidRuntimeException: Animators may only be run on Looper threads
at android.animation.ValueAnimator.cancel(ValueAnimator.java:1004)
at android.view.ViewPropertyAnimator.animatePropertyBy(ViewPropertyAnimator.java:965)
at android.view.ViewPropertyAnimator.animateProperty(ViewPropertyAnimator.java:921)
at android.view.ViewPropertyAnimator.alpha(ViewPropertyAnimator.java:735)
at com.design.zaton.prototypei.MainActivity$1$1.run(MainActivity.java:93)
at java.lang.Thread.run(Thread.java:761)
The app worked fine before with the same exact code but now it simply doesn't. I'm really confused.
Here's where the error happens:
new Thread(new Runnable() {
#Override
public void run() {
final String s = getGiphyViews(String.valueOf(mEdit.getText()));
runOnUiThread(new Runnable() {
#Override
public void run() {
result.setText(s);
}
});
loading.animate()
.alpha(0)
.setDuration(100);
done.animate()
.scaleY(1)
.scaleX(1)
.setDuration(300);
}
}).start();
The error outlines the loading.animate() method.
Thanks in advance!
runOnUiThread(new Runnable() {
#Override
public void run() {
//Your code
}
});
You have to execute the code in the UI Thread
Looper threads are threads in Android that permanently loop (or until you cancel them). They work in conjunction with Handlers which will post and send messages to Looper threads. Animators use heavy use of Looper threads because they perform their actions in repeated cycles. This allows the animator to not block after you press "start" so you can continue to perform other actions.
To further complicate matters, you most likely are performing animations on View objects. These can only be run on the main UI thread (which happens to be the biggest Looper thread of them all). So, you can not run these animations on separate threads like you are trying.
I think, there has been a solution for this using Handler. You can use postDelayed to minimal as 100 and run your animating tasks. In your case it would be:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
final String s = getGiphyViews(String.valueOf(mEdit.getText()));
runOnUiThread(new Runnable() {
#Override
public void run() {
result.setText(s);
}
});
loading.animate()
.alpha(0)
.setDuration(100);
done.animate()
.scaleY(1)
.scaleX(1)
.setDuration(300);
}
}, 100);
I had this problem today and above work resolved the problem. I would love to hear from anyone if there is any problem with this method.
Kotlin
If you still want to use a delay (or not)
Handler(Looper.getMainLooper()).postDelayed({
// Your Code
}, 1000)
Put Code Where Are getting error and doing any network operations
new Handler().post(new Runnable() {
#Override
public void run() {
// add your code here
}
});
I think you can create a main handler instance in your activity and override handle message method. you can save a handler quote in your work thread.When you finished work you can use handler to send a message and you receive message in handle message method. To start animation from handler message method and so on...
I am playing around with JMonkeyEngine.
While doing this i play JavaFX MediaPlayer.
This MediaPlayer takes a Runnable to handle what's to do, when the media finished:
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
}}
I want to do sth. like this:
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
// instance.toggleLists();
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}
});
this is working a couple of times, but finally i am running into some runtime error.
java.lang.IllegalStateException: Scene graph is not properly updated for rendering.
State was changed after rootNode.updateGeometricState() call.
Make sure you do not modify the scene from another thread!
Problem spatial name: Root Node
Yeah, that's true. I am messing up that thread from the outside.
As i am a little bit unused to this stuff...
I don't need to do that thing at that location in that run method, it's just what has to be done,when this is running.
What is the best way to pass over the work so that my ordinary update call can do that housework ?
I already tried to build in a flag, setting that to true and when true, updating that by the standard update call from the application itself, but somehow i ever run into this error. That didn't help me much.
The MediaPlayer just needs to tell my App "Hey! I'm ready! Give me a break and change me to something new!"
That is, what is happening in that run method.
You can use Application.enqueue to make a Runnable run on the main thread in the next update - like so: (assuming app is a reference to the Application)
mp.setOnEndOfMedia(new Runnable() {
#Override public void run() {
app.enqueue(new Runnable() {
#Override public void run() {
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}
});
}
});
If you're using Java 8, you can abbreviate this using lambda expressions:
mp.setOnEndOfMedia(() -> {app.enqueue(() -> {
initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
detachChild(node);
node = new TextureNode("mediaManagerTextureNode");
node.init(app, mp);
attachChild(node);
}});
I want to delay my application for a while while a melody is playing, and when it's finished change the image on an imageview.
public void addListenerOnButtons() {
harmonicaTecknad= (ImageView)this.findViewById(R.id.harmonicatecknadspelautblas);
harmonicaTecknad.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknadtryckrood);
RunAnimations();
utblas=MediaPlayer.create(SpelaTonerActivity.this, R.raw.utblas4);
utblas.start();
Thread timer = new Thread(){
public void run() {
try { // The delay should occur here
sleep(utblas.getDuration());
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1);
}
}
};
timer.start();
}
}
I get an exception error, obviously I cannot set the image inside the thread, so where should I set it?
This is all explained in details, with examples, in the android documentation:
Android offers several ways to access the UI thread from other
threads. You may already be familiar with some of them but here is a
comprehensive list:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Handler
[...]
Unfortunately, these classes and methods could also tend to make your
code more complicated and more difficult to read. It becomes even
worse when your implement complex operations that require frequent UI
updates.
To remedy this problem, Android 1.5 and later platforms offer a
utility class called AsyncTask, that simplifies the creation of
long-running tasks that need to communicate with the user interface.
Write harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1); code on UI thread because you can not write UI code to non UI thread.
So simply replace above line of code with
runOnUiThread(new Runnable()
{
#Override
public void run()
{
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1);
}
});
If you are still getting error then for testing purpose just change sleep(utblas.getDuration()); with sleep(1000);
As the other answers say, you need to set the image from the UI thread. However, while you can use Thread.sleep(), you should in general avoid using sleeps for logic. Most classes have some way to get callbacks when things happen - for example in your case you can use MediaPlayer.OnCompletionListener. You register for a callback from the media player, and that callback will always be on the UI thread. This is what it looks like:
public void addListenerOnButtons() {
harmonicaTecknad= (ImageView)this.findViewById(R.id.harmonicatecknadspelautblas);
harmonicaTecknad.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknadtryckrood);
RunAnimations();
utblas=MediaPlayer.create(SpelaTonerActivity.this, R.raw.utblas4);
utblas.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1);
}
};
utblas.start();
}
}