This is my code so far:
// Imported Classes
public class Timer extends Applet
{
public void paint (Graphics page) throws InterruptedException
{
Thread.sleep(1000);
}
}
I just want to know how I can get this to work. I've used the Thread.sleep() method in other code before, but never with Graphics. I don't have much experience with Exceptions either, I usually try my best to avoid or correct them.
You should never call methods such as Thread.sleep on the event dispatch thread (i.e. in paint methods). This will render the whole GUI unresponsive.
You should instead use timers such as SwingTimer to perform animations etc. See the following related questions:
how to use a swing timer to start/stop animation
Java Applet Thread Animation
How to make applet animation?
Drawing images continuously in Java Applet
Related
Currently I have a start menu for a game with a button which transform my menu background image from a PNG into a GIF after a button press. Now, I want my code to wait until the GIF animation is over. After that, it should continue normally (by opening a new JFrame with the actual game).
I've read some stuff about a swing timer, although I'm unsure of how to implement this as I am a Java beginner.
private ImageIcon a = new ImageIcon("a.png");
private ImageIcon b = new ImageIcon("b.gif");
class AddInterestListener implements ActionListener {
public void actionPerformed(ActionEvent event) {
bgLabel.setIcon(b); //replace PNG with GIF
//This here is where I want my delay to happen without freezing the GUI
JFrame game = new JFrame(); //Actual game frame starting etc.
}
}
Any suggestions?
You can't use blocking methods like Thread.sleep() or Thread.join() in Swing EDT. This will freeze the UI as Swing EDT handles all the UI refresh events.
You must implement this with events, first event blocks the UI second unblocks it. If you know the GIF animation length you can use SwingUtils.invokeLater() to run an async thread with that will fire the event after a fixed delay.
[Edit] apparently there was already an answer and I don't know if that answer , or my answer for that matter, fits in your software. One thing I can say for sure is that my method allows you to use custom scaling algorithms etc instead of the built-in one (but you probably don't need that either).
Afaik it is not possible to monitor the progress of a GIF displayed using SWING. You'll have to make your own GIF decoder/animator in order for you to 'detect' when the GIF is about to loop or end (yes animated GIFs can end).
For that I used a 3rd party loader from https://github.com/DhyanB/Open-Imaging to obtain the individual frames and timing information. No guarantee that this is still the best library out there as I found this little over a year ago.
From there on you'll need to write your own animator using javax.swing.Timer or similar.
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 using the latest Eclipse, and GWT Designer, to make a swing application in Java.
The main function in my application window (which is a javax.swing.JFrame) in the auto generated by the tools looks like this:
/* launch the application */
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
This seems like a lot of noise around what could have been just this:
public static void main(String[] args) {
try {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
I have read that the EventQueue.InvokeLater technique is required in some situations, and another question asks where to use it here.
My question is simpler; Why do this automatically in the code generator here? Why should main return quickly and let the application window get created later by the event queue? Wouldn't blocking be exactly the point? Why is the JFrame auto-generated designer doing this EventQueue stuff? I have tried to see some difference in the start up and showing of forms whether this code is done the simpler way or the harder way, and I can only conclude provisionally that this has some benefits that are not visible in tiny demo apps made by beginners like me, and that perhaps in real-world large complex Jframe based classes, there is some benefit to this delaying/queuing strategy?
Depending on your application and how it's being used, it's possible that there could be something that is drawing on the screen (and thus using the EventQueue) before or during the call to your main method. Calls that modify any UI components should be made on the Event Dispatch Thread, and this includes setting the application visible.
So just to be safe, it's a good practice to start your application on the EDT.
Why do this automatically in the code generator here?
It won't hurt, it's easy to generate, and it's considered good practice.
Why should main return quickly and let the application window get created later by the event queue?
It's possible that the main method is being called from some other application that is using the EDT and may have already drawn something on screen. If you draw your application directly in main, it's possible that your application may be altering some component that is in the process of being handled by something on the EDT, and potentially already drawn on the screen.
So just to be safe in case this situation ever happens, you should leave it up to the EDT to draw your application so it can do it when it won't interfere with anything else.
Wouldn't blocking be exactly the point?
Unless something else is calling main other than the JVM process that your user started by double-clicking the desktop icon, it's not going to make a difference when main returns as long as there is something on the screen.
I can only conclude provisionally that this has some benefits that are not visible in tiny demo apps made by beginners like me
You're right - most of the time it's probably not gonna make a difference, but I presume they included it because it was easy to generate & implement, it can't hurt, and it would exemplify good practice.
1) why is building Swing GUI inside try-catch-finally, I can't see any reason(s) for that, split create non thread safe GUI and non thread safe code to the separates threads,
2) Swing isn't thread safe, then correct is in all cases that pack() + setVisible(true) would be
last GUI rellated code lines
wrapped into invokeLater
forgot for examples from some code ExamplesDepots, this forum, another forums, sure these code works, but with risk that whatever/everything could happen
correct Swing GUI launch
for example
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
AppWindow window = new AppWindow();
window.frame.setVisible(true);
}
});
}
3) is there some Serializable, Custom L&F then (better would be) wrap into invokeAndWait
i am working on an applet with around ten different datasources(e.g. statistics/error-log/...). Each datasource is updated by a single network connection and reports updates via the observer mechanism. The applet has different views which display parts of the data. Every view is only interested in some parts of the data and registers itself as an Observer at the necessary Observables.
The views(extended JPanels) mostly consist of standard swing components (e.g. JLabels, JButton, ...). Some attributes of the components in the views depend on information from the underlying data model.
Example:
StatisticPanel::paintComponent(Graphics g) {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
super.paintComponent(g);
}
This logic is implemented in the paintComponent() method of the StatisticPanel and the update() methods just calls repaint(), because I didn't want the manipulate the components outside of the EDT.
Is this the intended way of updating swing components in a multi-threaded environment? Is it better to use a Runnable with SwingUtitlies.invokeLater()? Are there better approaches for this problem?
I second camickr's recommendations, but regarding this code snippet:
StatisticPanel::paintComponent(Graphics g) {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
super.paintComponent(g);
}
You have non-painting methods in your paintComponent method (the first two methods), and that shouldn't be as 1) you want this method to be as lean and fast as possible and thus have only painting-related code, and 2) you do not have aboslute control of when this method is called or even if it is called, and so non-painting related code and program logic does not belong in there. For these reasons, I strongly urge you to get them out of there, but instead should be called separate from paintComponent, but as with most Swing code, on the EDT.
EDIT 1
I'm not a professional, but how about if you gave your StaticPanel a method similar to this:
public void doMyUpdate() {
if (SwingUtilities.isEventDispatchThread()) {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
}
});
}
repaint(); // if the paintComponent method has more than just a super call.
}
EDIT 2
Also, please have a look at this thread: check-if-thread-is-edt-is-necessary
repaint() is used to invoke the Swing RepaintManger which in turn will schedule the repainting of the component, so yes it is ok to just invoke repaint directly. The RepaintManager will make sure all repainting is done on the EDT.
I've been spending a great deal of time trying to understand this. I created a JApplet that used Thread.sleep() in a loop to animate the applet. But when I tried to run the Applet the screen stayed blank. When I draw the animations in a separate thread and call repaint, the applet works perfectly. I've seen many explanations of why this happens but none have been very comprehensive.
What thread calls the paint method? And why can't that thread partially draw on the canvas, pause, then continue drawing? I've noticed that some Thread.sleep() calls work as expected, particularly when they are not in a loop.
UI needs to be repainted and this happens on UI thread.
Therefore you should not seize control of the UI thread - it seems that you are doing just this (animation loop with .sleep()).
You should return control of the UI thread (exit the function that you are in) so that it can be repainted.
Take a look at Swing Painting and SwingWorker to understand how to run a background thread to do some work and then update UI on UI thread.