This week's book giveaway is in the JavaScript forum.
We're giving away four copies of Cross-Platform Desktop Applications: Using Node, Electron, and NW.js and have Paul Jensen on-line!
See this thread for details.
Win a copy of Cross-Platform Desktop Applications: Using Node, Electron, and NW.js this week in the JavaScript forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Question about a Simple Animation on Head First Java  RSS feed

 
Xavier Wong
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, I am a Java beginner and currently reading Head First Java.
On chapter 12, there is a problem to construct a simple animation: a circle moves from the top left of the window to the bottom right. Below is the original code written by author, which works perfectly fine.

But I want to add a button to start movement manually, so I write something like this:

I run my program. Here's the result: after I click the button, the circle just waits for a while (because of Thread.sleep()) and then reappears at the ending point, lower right corner. My question is why? How to solve it?
 
Sam Gooding
Ranch Hand
Posts: 35
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Xavier Wong wrote:Hi, I am a Java beginner and currently reading Head First Java.
On chapter 12, there is a problem to construct a simple animation: a circle moves from the top left of the window to the bottom right. Below is the original code written by author, which works perfectly fine.

But I want to add a button to start movement manually, so I write something like this:

I run my program. Here's the result: after I click the button, the circle just waits for a while (because of Thread.sleep()) and then reappears at the ending point, lower right corner. My question is why? How to solve it?



Swing is optimizing the successive calls to repaint on the EDT. It's essentially coalescing all the closely invoked calls into one and executing it "later" where "later" is whenever Swing judges it should. The fact that you're looping in the EDT requesting the same panel be painted is just the kind of situation that Swing thinks it ought to delay painting. Curious to see just how long Swing would delay the update. Perhaps there's a limit on the (hypothetical) stack of repaints Swing is willing to see pile up before it takes action. Alternatively, Swing may invariably and blindly coalesce two closely spaced (in time) repaints which implies it would just delay the updating of the GUI without limit.

You need to replace repaint() with paintImmediately() and you'll see your circle move when it should.


 
Xavier Wong
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you Sam! I have solved the issue.

I guess that in my case, EDT would delay update for 50*250 milliseconds.
 
Rob Camick
Ranch Hand
Posts: 2787
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The example from Head First Java is not a very good example. It only works because it breaks the Swing rule that all Swing components should be created/modified on the Event Dispatch Thread. Read the section from the Swing tutorial on Concurrency in Swing for more information and examples on the proper way to create a GUI on the EDT.

You should NOT be using paintImmediately().

In the original code the looping is done on a separate Thread and the Thread.sleep() causes that Thread to sleep.

In your new code you start the code from the ActionListener which means your looping code is now executing on the Event Dispatch Thread and the Thread.sleep() is causing the EDT to sleep which means the GUI can't respond to events or repaint itself.

Don't use Thread.sleep().

Instead you should be using a Swing Timer to schedule the animation. Read the section from the Swing tutorial on How to Use Timers for more information.
 
Sam Gooding
Ranch Hand
Posts: 35
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

You should NOT be using paintImmediately().


just have to agree to disagree.. there is no "should" that properly applies here

If you know of a specific reason that in this circumstance - 1) within the EDT thread and 2) with the goal of producing real time rendering
of a specific component- that paintImmediately() should not be called, then that would be interesting. But note that a "reason" doesn't include things like "because you should do it this other way" or "the proper way is this other way" or "this other way is more useful generally in other circumstances" because of course those are self-validating arguments, i.e. specious.

In fact, this circumstance is the exact one that paintImmediately() is intended for- limited rendering of a specific component in real time . In this case the goal is pedagogical- he's learning about the how the EDT coalesces repaint() invocations .


So I disagree, there's nothing *wrong* with calling paintImmediately.
 
Rob Camick
Ranch Hand
Posts: 2787
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The proper solution is to design the program properly the way Swing was designed to be used.

Using paintImmediately in this case is being used to get around a problem because the program is not designed correctly.

So yes, it can be appropriate in in some places when you know and understand what you are doing, this is not one of those cases, because the OP does not realize that they are using an incorrect design for a Swing program. It does not fix the problem of the button being painted in its pressed state. It does not allow you to add a Stop button, for example, if you so desire because the GUI is still frozen and can't respond to events. You can't even click on the close button of the frame.

Proper Swing techniques and design should be suggested before resorting to less known solutions.
 
Sam Gooding
Ranch Hand
Posts: 35
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rob Camick wrote:The proper solution is to design the program properly the way Swing was designed to be used.


See now that's one of those self validating arguments I tried to warn you about

Rob Camick wrote:Using paintImmediately in this case is being used to get around a problem because the program is not designed correctly.


and again !



Rob Camick wrote:So yes, it can be appropriate in in some places when you know and understand what you are doing, this is not one of those cases, because the OP does not realize that they are using an incorrect design for a Swing program.
Proper Swing techniques and design should be suggested before resorting to less known solutions.


Doh!

Are there ways to update a component's view that would serve better in a wider array of circumstances? Sure. But the stated goal is to, in a SCCEE "program" to move the little green circle from point A to point B and have it update in real time. That's all. Anything else is not coming from the OP, and no one is asking how to design a general purpose graphics library. The answer to his question was what I posted- Swing is coalescing repaint calls- it does that. He is new to exactly that concept. Now he understands it . Game over, mission accomplished.

Even within the context of GP graphics game engine, paintImmediately is 100% legit. There is nothing "cheating" , slipshod or otherwise undesirable about using paintImmediatelyi; it's not deprecated it's not advised against; it's not anything. It's just a method call used in some circumstances, specifically this one. If you want I can link to the Amy Fowler article that says the same thing. paintImmediately is not a dangerous call or indicative of bad design in this situation.




 
Rob Camick
Ranch Hand
Posts: 2787
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The OP is trying to understand why the first example works and the second doesn't.

The most obvious symptom that there is a problem with the code is that the oval doesn't move, but there are other symptoms as well such as the button not repainting and the frame not closing. The paintImmediately() suggestion will fix the first symptom but not the others.

Your answer does not explain all the symptoms. The problem is more than just coalescing painting calls. If this was the only problem then the button should be repainted properly but it is not because the state of the button model has been frozen because Swing is no longer responding to events.

To understand why the second approach doesn't work you need to understand how the EDT works and how Swing was designed to be used. The reason why the oval doesn't move and the reason why the button is frozen and the reason why you can't close the frame are all related. It is because the EDT is sleeping. The reason why the EDT is sleeping in the second case an not the first is because the go2() method is invoked from the ActionListener. This reason why this is important is because all code executed from an ActionListener is executed on the EDT. So if your code does anything to cause the EDT to "sleep", then you are causing the GUI to become unresponsive.

Just because you can use paintImmediately() does not mean you should use it. Even the API says you should rarely use it. Learning how to do basic painting should not involve using rarely used techniques.

Understanding how to use the EDT properly is fundamental in learning how to use Swing properly. I am providing this information for the benefit of the OP.
 
Sam Gooding
Ranch Hand
Posts: 35
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rob Camick wrote:The OP is trying to understand why the first example works and the second doesn't.

Your answer does not explain this. It is doing more than just coalescing painting calls. If this is all it was doing then the button should be repainted properly but it is not because the state of the button model has been frozen because Swing is no longer responding to events.


That is just provably wrong.

The exact and only reason the GUI wasn't responding was because the repaint() calls were being coalesced in the AWT Event Queue. It's the AWT thread that is executing the loop variable, the sleep, the repaint and the output command:
System.out.println("VALUE OF X AND Y : " + x + " " + y);

All of these do in fact occur, one after the other as expected. The loop is incremented. The AWT thread sleeps briefly. The repaint is invoked. The System.out.println is executed. The only one of those which doesn't have the expected effect is the repaint() command which does not result in the GUI being updated. The loop variable is updated. The sleep does happen. The System.out.println does print to the screen.

If the AWT thread on which ALL these is being run were sleeping and not continuing, then none of them would happen.


In fact, because the loop effectively controls when the program will end, if the AWT thread were sleeping, the program would simply freeze completely and never terminate because it is the AWT thread incrementing the counter.


Furthermore, if the sleep WERE the problem then removing it would solve the OP's problem. Yet, it doesn't.

Removing the sleep has no effect on updating the GUI, although this isn't obvious since the program ends very quickly and the lack of GUI responsiveness is therefore not as obvious as it is when the sleep is present.

Still, we can show that the repaints are in fact being coalesced and the GUI is therefore not updating in response to the calls to repaint().

When repaint() is called, Swing invokes paintComponent(). Inserting a a debugging statement into paintComponent will therefore show how many times it's called.

If we actually do these two things- remove the sleep() and insert a debugging statement into paintComponent (we insert "OPP.test.MyPanel.paintComponent" ) and run the resulting program , we see this, we can see that p[aintComponent() is not being invoked in response to reapint():

OPP.test.MyPanel.paintComponent
OPP.test.MyPanel.paintComponent
OPP.test.MyPanel.paintComponent
OPP.test.MyPanel.paintComponent
threadName = AWT-EventQueue-0
VALUE OF X AND Y : 1 1
VALUE OF X AND Y : 2 2
VALUE OF X AND Y : 3 3
VALUE OF X AND Y : 4 4
VALUE OF X AND Y : 5 5
VALUE OF X AND Y : 6 6
VALUE OF X AND Y : 7 7
VALUE OF X AND Y : 8 8
VALUE OF X AND Y : 9 9
VALUE OF X AND Y : 10 10
VALUE OF X AND Y : 11 11
VALUE OF X AND Y : 12 12
VALUE OF X AND Y : 13 13
VALUE OF X AND Y : 14 14
VALUE OF X AND Y : 15 15
VALUE OF X AND Y : 16 16
VALUE OF X AND Y : 17 17
VALUE OF X AND Y : 18 18
VALUE OF X AND Y : 19 19
VALUE OF X AND Y : 20 20
VALUE OF X AND Y : 21 21
VALUE OF X AND Y : 22 22
VALUE OF X AND Y : 23 23
VALUE OF X AND Y : 24 24
VALUE OF X AND Y : 25 25
VALUE OF X AND Y : 26 26
VALUE OF X AND Y : 27 27
VALUE OF X AND Y : 28 28
VALUE OF X AND Y : 29 29
VALUE OF X AND Y : 30 30
VALUE OF X AND Y : 31 31
VALUE OF X AND Y : 32 32
VALUE OF X AND Y : 33 33
VALUE OF X AND Y : 34 34
VALUE OF X AND Y : 35 35
VALUE OF X AND Y : 36 36
VALUE OF X AND Y : 37 37
VALUE OF X AND Y : 38 38
VALUE OF X AND Y : 39 39
VALUE OF X AND Y : 40 40
.
.
.
VALUE OF X AND Y : 58 58
VALUE OF X AND Y : 59 59
VALUE OF X AND Y : 60 60
VALUE OF X AND Y : 61 61
VALUE OF X AND Y : 62 62
VALUE OF X AND Y : 63 63
VALUE OF X AND Y : 64 64
VALUE OF X AND Y : 65 65
VALUE OF X AND Y : 66 66
VALUE OF X AND Y : 67 67
VALUE OF X AND Y : 68 68
VALUE OF X AND Y : 69 69
VALUE OF X AND Y : 70 70
.
.
.
VALUE OF X AND Y : 87 87
VALUE OF X AND Y : 88 88
VALUE OF X AND Y : 89 89
VALUE OF X AND Y : 90 90
VALUE OF X AND Y : 91 91
VALUE OF X AND Y : 92 92
VALUE OF X AND Y : 93 93
VALUE OF X AND Y : 94 94
VALUE OF X AND Y : 95 95
VALUE OF X AND Y : 96 96
VALUE OF X AND Y : 97 97
VALUE OF X AND Y : 98 98
VALUE OF X AND Y : 99 99
VALUE OF X AND Y : 100 100
VALUE OF X AND Y : 101 101
VALUE OF X AND Y : 102 102
VALUE OF X AND Y : 103 103
VALUE OF X AND Y : 104 104
VALUE OF X AND Y : 105 105
VALUE OF X AND Y : 106 106
VALUE OF X AND Y : 107 107
VALUE OF X AND Y : 108 108
VALUE OF X AND Y : 109 109
VALUE OF X AND Y : 110 110
VALUE OF X AND Y : 111 111
VALUE OF X AND Y : 112 112
VALUE OF X AND Y : 113 113
VALUE OF X AND Y : 114 114
VALUE OF X AND Y : 115 115
VALUE OF X AND Y : 116 116
VALUE OF X AND Y : 117 117
VALUE OF X AND Y : 118 118
VALUE OF X AND Y : 119 119
VALUE OF X AND Y : 120 120
VALUE OF X AND Y : 121 121
VALUE OF X AND Y : 122 122
VALUE OF X AND Y : 123 123
VALUE OF X AND Y : 124 124
VALUE OF X AND Y : 125 125
VALUE OF X AND Y : 126 126
VALUE OF X AND Y : 127 127
VALUE OF X AND Y : 128 128
VALUE OF X AND Y : 129 129
VALUE OF X AND Y : 130 130
VALUE OF X AND Y : 131 131
.
.
.
VALUE OF X AND Y : 177 177
VALUE OF X AND Y : 178 178
VALUE OF X AND Y : 179 179
VALUE OF X AND Y : 180 180
VALUE OF X AND Y : 181 181
VALUE OF X AND Y : 182 182
VALUE OF X AND Y : 183 183
VALUE OF X AND Y : 184 184
VALUE OF X AND Y : 185 185
VALUE OF X AND Y : 186 186
VALUE OF X AND Y : 187 187
.
.
.
VALUE OF X AND Y : 216 216
VALUE OF X AND Y : 217 217
VALUE OF X AND Y : 218 218
VALUE OF X AND Y : 219 219
VALUE OF X AND Y : 220 220
VALUE OF X AND Y : 221 221
VALUE OF X AND Y : 222 222
VALUE OF X AND Y : 223 223
VALUE OF X AND Y : 224 224
VALUE OF X AND Y : 225 225
VALUE OF X AND Y : 226 226
VALUE OF X AND Y : 227 227
VALUE OF X AND Y : 228 228
VALUE OF X AND Y : 229 229
VALUE OF X AND Y : 230 230
VALUE OF X AND Y : 231 231
VALUE OF X AND Y : 232 232
VALUE OF X AND Y : 233 233
VALUE OF X AND Y : 234 234
VALUE OF X AND Y : 235 235
VALUE OF X AND Y : 236 236
VALUE OF X AND Y : 237 237
VALUE OF X AND Y : 238 238
VALUE OF X AND Y : 239 239
VALUE OF X AND Y : 240 240
VALUE OF X AND Y : 241 241
VALUE OF X AND Y : 242 242
VALUE OF X AND Y : 243 243
VALUE OF X AND Y : 244 244
VALUE OF X AND Y : 245 245
VALUE OF X AND Y : 246 246
VALUE OF X AND Y : 247 247
VALUE OF X AND Y : 248 248
VALUE OF X AND Y : 249 249
VALUE OF X AND Y : 250 250
OPP.test.MyPanel.paintComponent


the debug println statement which outputs: OPP.test.MyPanel.paintComponent executes just five (!!) times , four of which happen BEFORE the button is pushed and the loop containing the calls to repaint() begins. These calls are made while the program is being realized ! (note: OPP is my shorthand for: other people's problems!)


To understand why the second approach doesn't work you need to understand how the EDT works and how Swing was designed to be used.


It IS important to understand this, I concur.

The reason why the oval doesn't move and the reason why the button is frozen and the reason why you can't close the frame are all related. It is because the EDT is sleeping.


Just wrong. As demonstrated above.

The reason why the EDT is sleeping in the second case an not the first is because the go2() method is invoked from the ActionListener. This reason why this is important is because all code executed from an ActionListener is executed on the EDT. So if your code does anything to cause the EDT to "sleep", then you are causing the GUI to become unresponsive.


Nothing new here. It's still just wrong as proved above.

Just because you can use paintImmediately() does not mean you should use it. Even the API says you should rarely use it. Learning how to do basic painting should not involve using rarely used techniques.


That is not true and none of the the clauses of that sentence are true.

Understanding how to use the EDT properly is fundamental in learning how to use Swing properly. I am providing this information for the benefit of the OP.

This is a platitude, and in no way supports your flawed reasoning.

Repectfully,

 
Sam Gooding
Ranch Hand
Posts: 35
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here is the SCCEE , with the println inserted and the sleep removed which is responsible for the above output.


import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class test
{
public static void main(String[] args)
{
test a = new test();
a.go();
}

void go()
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new MyPanel();
button1 = new JButton("push");
//panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
frame.getContentPane().add(panel);
frame.getContentPane().add(BorderLayout.SOUTH, button1);
button1.addActionListener(new buttonlistener());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.pack();
frame.setVisible(true);
}

void go2()
{
String threadName = Thread.currentThread().getName();
System.out.println("threadName = " + threadName);
for (int i = 0; i < 250; i++)
{
x++;
y++;
/* try
{
Thread.sleep(1);
} catch (Exception ex)
{
}*/
panel.revalidate();
panel.repaint();



System.out.println("VALUE OF X AND Y : " + x + " " + y);

}
}

class buttonlistener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
go2();
}
}

class MyPanel extends JPanel
{
public void paintComponent(Graphics g)
{
System.out.println("OPP.test.MyPanel.paintComponent");
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.green);
g.fillOval(x, y, 40, 40);
}
}

int x;
int y;
private JFrame frame;
private MyPanel panel;
private JButton button1;
}
 
Rob Camick
Ranch Hand
Posts: 2787
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I suggest you read the link I provided earlier on "Concurrency in Swing". It will provide you with more information on Swing's single threaded rule and on how the EDT works with Swing.

When you start the program a regular Thread is created. This is easily demonstrated by adding



in the main() method. On my machine the Thread is called "main".

1) When you click on the "Start" button the ActionListener code is placed on the EDT for processing. This is a different Thread (known as the EDT). On my machine it is called "AWT-Event-Queue-0".
2) In the ActionListener there is a tight loop that updates the x/y variables, invokes a repaint() and then goes back to sleep.
3) The repaint() request is sent to the RepaintManager and the RepaintManager coalesces painting events and will eventually add a painting request to the end of the EDT.
4) Now the key with the EDT is that all requests are processed sequentially. So the painting request cannot be executed UNTIL the ActionListener has finished processing its code. This means the ActionListener must perform all 250 of the loop iterations BEFOE the painting request can be handled. This is what effectively causes the EDT to freeze.
5) Once the loop is finished executing the painting request is handled, the paintComponent() method is executed and the oval is shown at it final position because the x/y values have been updated in the loop.

Maybe the Paint Processing section from the Java article on Painting in Swing will help.

The reason you see the System.out.println(...) output is because console output is done on a different Thread than the EDT. So that thread is free to display results on the console as they are generated.

That is as simple as I can make the explanation of what is happening. Understanding the EDT and Swing's single threaded rule is important for designing responsive GUI's.
 
Sam Gooding
Ranch Hand
Posts: 35
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rob Camick wrote:I suggest you read the link I provided earlier on "Concurrency in Swing". It will provide you with more information on Swing's single threaded rule and on how the EDT works with Swing.

When you start the program a regular Thread is created. This is easily demonstrated by adding



in the main() method. On my machine the Thread is called "main".

1) When you click on the "Start" button the ActionListener code is placed on the EDT for processing. This is a different Thread (known as the EDT). On my machine it is called "AWT-Event-Queue-0".
2) In the ActionListener there is a tight loop that updates the x/y variables, invokes a repaint() and then goes back to sleep.
3) The repaint() request is sent to the RepaintManager and the RepaintManager coalesces painting events and will eventually add a painting request to the end of the EDT.
4) Now the key with the EDT is that all requests are processed sequentially. So the painting request cannot be executed UNTIL the ActionListener has finished processing its code. This means the ActionListener must perform all 250 of the loop iterations BEFOE the painting request can be handled. This is what effectively causes the EDT to freeze.
5) Once the loop is finished executing the painting request is handled, the paintComponent() method is executed and the oval is shown at it final position because the x/y values have been updated in the loop.

Maybe the Paint Processing section from the Java article on Painting in Swing will help.

The reason you see the System.out.println(...) output is because console output is done on a different Thread than the EDT. So that thread is free to display results on the console as they are generated.

That is as simple as I can make the explanation of what is happening. Understanding the EDT and Swing's single threaded rule is important for designing responsive GUI's.





Come on! In 4 you are changing your reasoning entirely for why the GUI is stalled:
4) Now the key with the EDT is that all requests are processed sequentially. So the painting request cannot be executed UNTIL the ActionListener has finished processing its code. This means the ActionListener must perform all 250 of the loop iterations BEFOE the painting request can be handled. This is what effectively causes the EDT to freeze.



Whereas before you claimed:

The reason why the oval doesn't move and the reason why the button is frozen and the reason why you can't close the frame are all related. It is because the EDT is sleeping.



And with respect to the System.out.println, they are indeed printed to the screen in another thread, however, the call System.out.println (aka SOUT) itself is made in the EDT in this program, and that is what is relevant. It shows the EDT is not sleeping. If the EDT were sleeping, the call wouldn't have been made at all, irrespective of what thread actually does the printing to standard output. So even mentioning this third thread, the standard output thread, is a total red herring with respect to the fact that what you're telling the OP is incorrect. The EDT is not sleeping, as you asserted, and is therefore not the cause of the frozen GUI.


To the OP:

from Oracle's site:

http://www.oracle.com/technetwork/java/painting-140037.html


Synchronous Painting

As described in the previous section, paintImmediately() acts as the entry point for telling a single Swing component to paint itself, making sure that all the required painting occurs appropriately. This method may also be used for making synchronous paint requests, as its name implies, which is sometimes required by components which need to ensure their visual appearance 'keeps up' in real time with their internal state...

Programs should not invoke this method directly unless there is a valid need for real-time painting. This is because the asynchronous repaint() will cause multiple overlapping requests to be collapsed efficiently, whereas direct calls to paintImmediately() will not. Additionally, the rule for invoking this method is that it must be invoked from the event dispatching thread; it's not an api designed for multi-threading your paint code!.



Also, aside from the coalescing of repaint requests- which is why we don't see 250 paintComponents debugging printlns - it is true that repaint and revalidate are the 2 (of 2) special Swing method that unlike other methods in Swing components are what's known as "thread safe.", as I mentioned, which just means that despite effecting a Swing component, they can be invoked from any thread and not just the EDT. This is achieved by creating a new request which is ultimately placed on the EDT. In the current program, this does place them behind the actionPerformed, and this is effecting the order of execution.


The stalling of your GUI had nothing to do with sleeping threads and for the purpose you presented using paintImmediately was entirely appropriate in every sense.

Rob Carmick- nice to meet you. After reviewing a largish number of your other posts here on coderanch I would request that you just not address me directly, although of course we may both be answering some future threads. Thanks for understanding and know I'll return the favor. Peace.






 
Xavier Wong
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Many thanks to both of you, Sam and Rob!
I can't quite understand some topics in your argument and I haven't finished the book yet. As soon as I get enough understanding on thread and EDT, I would come back here.
 
Rob Camick
Ranch Hand
Posts: 2787
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Please look at my original comment:

In your new code you start the code from the ActionListener which means your looping code is now executing on the Event Dispatch Thread and the Thread.sleep() is causing the EDT to sleep which means the GUI can't respond to events or repaint itself.


I later stated that processing is indeed being done for the ActionListener code, but no other events including the repainting can be done until the ActionListener processing is completed. I did not change my reasoning, I only attempted to clarify what I meant by the term "sleeping" to make my initial statement easier to understand.

The EDT is not sleeping, as you asserted, and is therefore not the cause of the frozen GUI.


The EDT will execute the 5-6 statements in the for loop and then it will go back to sleep. So, until the ActionListener code finishes executing the EDT is "effectively sleeping" because no new events can be processed, so the GUI can't repaint itself. I did not mean to imply that the code from the ActionListener was not executing every time the Thread wakes up.


To the OP:

I hope you are not satisfied with the paintImmediately(...) solution. I know most people like the "one line solution". However, I still hope you take the time to read the tutorial on "Concurrency" to better understand how important it is to not execute long running tasks on the EDT because this will prevent the GUI from responding to user interaction. Users don't like it when the GUI freezes for no apparent reason.

Since you have the Start button working, I now challenge you to add a "Stop" button so you can stop the oval from moving. Just a warning that you won't be able to get it working using the paintImmediately() approach, because the "Stop" button will not respond to clicking until the ActionListener loop is finished and the oval is already at the bottom. My original suggestion to use a Timer is still applicable. You start the Timer when you click "Start" and stop the Timer when you click "Stop".
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!