Make your GUI more responsive

In the program, I visualize physical modeling (mostly). Now it works, but it can be very unresponsive, and I think I know why - too many (read: all) calculations are performed in the event stream.

When you press the play button, a Swing Timer is created that wakes up periodically and calls updateTime() - so far so good. The problem is that updateTime() through each time-dependent object and tells it to propagate forward over time by the corresponding amount (either real-time elapsed time or an arbitrary unit of time for each tick). These calculations and subsequent GUI updates are in the event dispatch stream.

So, I would like to offload as many of these calculations as possible, and I think SwingWorker is the way to go, but I'm not sure how to work with them in existing code. I cannot have existing classes extend with SwingWorker , as many of them already extend other classes.

My best idea is to create an interface for every time-dependent object to implement. The interface will define two methods: calcUpdateTime() and drawUpdateTime() . I would separate each of my current updateTime() methods into physics calculations (in calc_ ) and GUI updates (in draw_ ). Then I will create only one SwingWorker class that takes a TimeDependant object in the constructor, and its doInBackground will call calcUpdateTime and done will call drawUpdateTime . Therefore, I can replace all occurrences

 myObj.updateTime(currentTime); 

from

 new MySwingWorker(myObj, currentTime).execute(); 

I wanted to launch this idea of ​​SO, because it is not quite right, and I would like to avoid reorganizing the whole project to find out that I started with a bad idea. Also, isn't it a bad idea to create potentially dozens of MySwingWorker every tick?

Thanks for reading this.

+4
source share
2 answers

You are right, there is no need to call SwingWorker.execute() for each worker for each tick, because you will create and destroy many threads that you really do not need.

However, using SwingWorker is still a good idea, simply because it gives you an easy way to separate the code that should be running in the background (your implementation of SwingWorker.doInBackground() ) from the code that must be run in Swing to update GUI afterwards (your implementation of SwingWorker.done() ).

Instead of using javax.swing.Timer or java.util.Timer I would recommend using java.util.concurrent.ScheduledThreadPoolExecutor . Basically, it can do whatever java.util.Timer can do, except that it also gives you the ability to control how many threads are running in the background, how to handle exceptions that are thrown in the background thread, etc.

+2
source

I had a bad impression (in performance) using a Swing timer. Since all events in Swing use the same thread, it seems to have quite a few delays.

I also suggest trusting your instincts about multiple instances of swinging work frames every tick. That doesn't seem right to me either. (And according to the SwingWorker , it is designed to run only once, so you cannot safely reuse it).

A timer that can do what you need is java.util.Timer . This has quite a few options for specifying timeouts, although depending on the accuracy of your time simulation, even this may not be acceptable. (For example: if you want it to run in real time, but your calculations actually take longer than in real time, what should it do? Start slowly or start skipping time steps?)

So, not knowing exactly what calc / draw is in your program, I would suggest that you try java.util.Timer . When it expires (after any time interval that you find appropriate based on your "real-time multiplier"), skip all the calculations and then drop the results back into the EDT stream to make a drawing (for example, wrapping them in SwingUtilities.invokeLater() )

Of course, this can cause locking issues if the EDT wants to reference the same objects as the computation flow. Ideally, if the downstream can pass unmanaged results to the EDT, this eliminates the need to enter locks.

(Disclaimer: none of the above takes into account several cores / processors, except one for the graphical interface, one for calculations. If you want to parallelize the application, this is probably not the right solution).

0
source

Source: https://habr.com/ru/post/1301664/


All Articles