This week's book giveaway is in the OCAJP 8 forum. We're giving away four copies of OCA Java SE 8 Programmer I Study Guide and have Edward Finegan & Robert Liguori on-line! See this thread for details.
I'm writing a program that plays a simple version of the game of Nim, with 11 coins. When the player presses on any of the last three coins on the screen, that coin all the coins to its right turn red; when the mouse is released, the marked coins should be removed immediately and then the computer makes its move, coloring one, two, or three of the remaining coins yellow, pausing for one second, and finally removing them from the screen. Now, what happens in my implementation is this: instead of pausing after marking the coins the computer is supposed to remove, it appears the execution is paused right after the mouse is released - the red coins remain on the screen for one more second, and then all the coins are removed at once – both the player’s and the computer’s, so that you can’t even see the computer’s coins turning yellow (I hope this is clear enough )
What am I missing here?
I haven't studied your program in depth, but I did notice you have a pause in your action routine. I don't think this is going to pause the UI's between an early part of the UI getting updated and a later part; quite probably the program likely isn't going to repaint the GUI until after this routine returns. From the UI handler's point of view, you might have several other controls that you want to update, and it is best for it to get all of your code executed before it does updating to avoid flicker and just generally to run more smoothly.
You might consider setting a timer of some sort; when the timer fires, do the next stage of UI updating that you want to do. Remember that you should only update the UI on the UI dispatch thread in Swing, and you might consider disabling user input while that's going on.
Joined: Oct 23, 2011
Thanks for the reply, Ralph
Unfortunatelly, I am not sure what you mean by a timer (or, in fact, by a "dispatch thread" - nor do I know how to disable user input) ... If it's any excuse, I am a total beginner
But this exercise is from a book I am studying from (The Art and Science of Java, I got to chapter 11 - although this probably doesn't mean anything to you), so I know I should be familiar with all the tools I need to get this right...
Anyway, thanks again
Joined: May 29, 2005
Well, it seems to me this exercise is at least medium level -- UI programming, assuming that's what you're doing (point and click interface, implied by a mouse handler) is a little tricky, to my mind, for a beginner.
UI code, especially Java Swing, often works this way: the user clicks something on the screen, and the UI framework detects that and calls one or more "listener" routines. That is how I expect "mouseReleased" got called; you don't have any code that calls mouseReleased(), it's called by your UI framework.
Further, once a "listener" routine like mouseReleased is called, the UI framework lets it run to completion, and maybe other listeners, and only then does it decide "ok, let's update the picture on the screen so that it matches any changes that take place." If that is what is happening here, you can change the color of the coins, but if you remove them in the same listener, then the color change never shows up, because by the time the UI framework updates the screen, the code to remove those coins has already run.
So it seems to me you want the mouseReleased routine to run to completion with only the color change having been done. Therefore, you need something to notify the program when a certain length of time has passed, and I was calling that a timer routine. I don't know if your lessons have included javax.swing.timer, but it looks like it is suited to your purpose; you would instantiate this timer with the delay you want, give it an action routine that would remove the coins, set it so it does not repeat, and start it, all before leaving the mouseReleased routine. After the timer fires, it calls your action routine and removes the coin. An advantage of javax.swing.timer over other methods is that it is already set up to operate in the UI thread, which is necessary for Swing.
If you aren't using Swing, then you'll need to find something similar with whatever tools you have. You can write your own timer, but I really do think that is beyond beginners, depending as it does on creating a runnable object and feeding it to a different thread.
Campbell Ritchie wrote:I have added code tags. Use spaces, not tabs for indenting.
You would have to show us the details of the pause method for us to know what is going on. The usual way to pause is to use the Thread.sleep() method. Beware: that declares a checked Exception.
But we never, never call sleep() (or pause(), or anything of the sort) on the event thread; that's what the whole problem is here.
I'll strengthen Ralph's assertions for you: this is absolutely what your problem is. Remember that the screen will never be updated during any of your event handler methods; all the updates will wait till the end. Therefore whenever you need to do anything in an event handler that involves time -- i.e., this happens, then that happens -- you need to use your event handler to set up a separate parallel set of code, called a Thread, and fire it off, so that it continues to run and allows the event handler to return right away, letting Java get back to its important business of painting the screen and handling more events.
Unfortunately, I am not familiar with threads and I think the point of the exercise is to make do with the scant tools I have at my disposal. I guess I will give up after all
But thank you all for your help, guys
Well, I just couldn't let go of this problem, and I really wanted to solve it without using any new classes and methods - because I think that was sort of the point of the exercise.
Anyway, here's my new solution. I ran it only a couple of times, but it appears to be working fine .
I realize this is probably not the most efficient (and definitely not the most elegant) way to solve it, but here it is anyway
I couldn't have done it without your help, so thanks again