I have a JPanel on which I wish to have several threads painting "animations" on. An "animation" consists of a JLabel with an ImageIcon on it, which is being moved from one area of the screen to another area.
Now, problem is - I want several such animations to be portrayed on screen by those threads mentioned. Problem is - the JPanel's "paint()" method can only be trigged by one thread at a time - causing the animations to execute serially, instead of in a parallel way.
Any idea how to have several such animations on screen at the same time?
It is impossible to use multiple threads to do what you want. Swing Toolkit is single threaded
. The correct way to do it is to use one of the animation frameworks available:
Trident animation framework
TimingFramework
Swing is not thread-safe, thus it's simply not a supported use-case to do UI-related stuff from several threads simultaneously.
Go for the model-view-controller (MVC) pattern:
Let all threads update a (thread safe) model.
Whenever there is an update of the model, invoke repaint.
repaint() will schedule the UI-thread to call the proper paint-methods.
The paint-method should then simply read the state of the model, and draw the component accordingly.
Related
I'm designing a game where you get to the edge of the screen the screen will shift to a new panel of the same map similar the first Zelda game. Which method would be more efficient and or effective, having a thread running using repaint() or would using javax.swing.Timer and calling super.paintComponet work better?
Usually for simple animations, you can use javax.swing.Timer But it looks like you are into a more complex game. If you continue to use swing.Timer and if your execution of the codes are not fast enough, it may affect the painting of your components causing your UI to be irresponsive.
You can construct a game loop and render according to the frame rate you wanted by invoking Thread.sleep(delay) via a worker thread remember do not run it in the Event Dispatch Thread, else your UI will also become irresponsive.
For some UI components in our application, we override paintComponent, which under some conditions "recursively" calls itself by invoking repaint. We use this approach to achieve high refresh rate of animations in the component.
For instance, a progress bar we use looks something like:
public class SimpleProgressBar extends JPanel {
private boolean inProgress;
....
#Override
protected void paintComponent(Graphics g) {
if (inProgress) {
paintBar(g);
repaint();
} else {
doSomeOtherThings();
}
}
}
Is this a good practice (especially in terms of performance / efficiency / CPU usage)?
Is it better to use a Timer or a background thread to repaint our components?
Is this a good practice (especially in terms of performance / efficiency / CPU usage)?
No, it is not good practice. Calling repaint from within paintComponent is bad practice because:
A high frame rate like this is virtually never required
The frame rate is not guaranteed (repaint does not directly call the painting method, but causes a call to this component's paint method as soon as possible' (which may not be immediately))
Places priority on painting of a single component, and can result in poor performance not only in painting of that one component, but also painting of other Components as well as response to other EDT specific tasks (eg events)
Is it better to use a Timer or a background thread to repaint our components?
Yes, using a Timer or Thread gives you much better control over the frame rate, without bogging down the EDT while doing so. Depending upon the context, a Timer runs on the EDT (as opposed to a Thread) so no dispatching to the EDT is required.
There are very few situations where overriding paintComponent is a good thing. Your situation seems to be one of them; however, it is important to remember that it is not your job to call paintComponent. What I mean by this, is that it is an office of the System to decide when to repaint certain components. This is especially evident when you drag the screen around, or when you put another screen over yours. That being said, it is very difficult to say how many times your method will be called; therein, making it difficult to say when it would be worth using that implementation.On a side note, a background thread, as you put it, would more than likely not make it better, and Swing is notoriously not thread-safe.I hope this helps, and best of luck to you!
I am about to write an animation in which a character on a JPanel moves left/right when the user presses (and holds) the appropriate keys.
Now, since I am new to concurrency I want to ask : should the code handling the animation (namely the method that will move and repaint the character as long as the key is held) be executed on a worker thread or the event dispatch thread ?
I read the tutorials on concurrency in swing, and it seems that stuff that changes the components (in this case it's painting JPanel) should be on the event handling thread, but on the other hand that would freeze all the other events as long as a key would be held right ?
For example a user won't be able to pause the game while he's holding the go-left key, if I understand this correctly. So which approach is correct and why? Or maybe there is totally different way to make such an animation ?
Thank you in advance!
All the Drawings Paintings need to be done on EDT thread. Never on any other Thread . Use
SwingUtilities.invokeLater() .. for your painting. You can do calculations like what will be the next postion of your character on Worker Thread. You won't have any unresponsiveness if you are doing creating and using Swing Classes on EDT. just Make sure that your computation is not too long. For Animation whenever you find the next positon of your Character just call
SwingUtilties.invokeLater to update changes on UI
In all my time so far working with Java and its Swing GUI framework, I've never quite figured out (or even attempted to try) how to make the interface animate components.
Say I wanted the screen to slide left into the next screen or have a JLabel "fly" to a new location. Perhaps you want a menu to smoothly open in an animated fashion. How does this work?
Do you have to use SwingWorker? Even if that's the case... how can you control the painting of components if the layout manager is already doing that?
Have a look at the book Filthy Rich Clients, you will find some really good answers there.
I think that there no reason for use SwingWorker, SwingWorker is designated for running long Backgroung Task(s) on output would be on Event dispatch Thread,
For animations in Swing is there javax.swing.Timer, examples here
Take a look at Trident library. You can use it to interpolate various properties in your class.
I'm using the java swing library to develop a board game called DAO.
The problem is that after the human player makes its move, by clicking on the JButton with the piece image that he wants to play, I call the computer AI routine but inside the mouse event function. By doing this only when the function returns, the computer ends its turn, do the JButtons refresh their Images (setIcon comes in).
I'd like to know how can I force the JButtons to change their image at the moment they are clicked and not only when the mouse event function ends (as I need to handle data inside it).
I've tried all of this
myButtons[i][j].setIcon(xIcon);
myButtons[i][j].revalidate();
myButtons[i][j].repaint();
myButtons[i][j].validate();
None worked.
Thx in advance
You may want to try putting the action performed upon clicking the JButton into a Swing worker. This will allow the task to go on in the background, while the user can still click other buttons, etc.
See http://java.sun.com/docs/books/tutorial/uiswing/concurrency/simple.html.
There is a single thread used for all Swing activity.
Here's the process.
One event appears on the event queue
it is pulled from the queue and executed by The AWT Thread
Any new events created while this is executing are placed on the queue to be held until the currently running AWT event returns.
The event executing returns and the next event on the queue is dequeued and executed.
This means that if you need to do anything that takes more than, say 1/100 of a second or so, you shouldn't do it any thread started from a swing event. Instead, spawn your own thread and return the swing thread to the system so the GUI can be updated.
Now, your thread MUST NOT update any GUI objects! If you need to update a GUI object, use invokeLater to place your code back on the AWT thread.
New Java programmers not conforming to this rule and executing tasks on the AWT thread is almost certainly the biggest reason people think Java is slow.