Making moving motion with labels using threads in java - java

I'm having a problem I'm making a pool game and I need the ballos to react when I simulate a hit, the program works like this, you click the direction and power to hit the ball and the click go, the go button is in the GUI class where my labels are created, the button calls a method from my main class that recieves the parameter and then with a while in it, changes the X and Y of the ball till the power is reduced to 0 and then stops, the code is working, but the ball moves until the while stops. So the while works and when the power int is 0 the while goes out and then the new X,Y are painted.
This is the funcion that the button calls, the button sends all the parameters
public void golpe(int pbola, int pvelocidad, String pdireccion, JLabel[] listalabels) throws InterruptedException{
listabolas[pbola].setVelocidad(pvelocidad);
listabolas[pbola].setDireccion(pdireccion);
while (listabolas[pbola].getVelocidad() > 0) {
moverBola(pbola, listalabels);
//System.out.println(listabolas[pbola].getPosX());
//System.out.println(listabolas[pbola].getPosY());
Thread.sleep(500);
//This line is supposed to change the X and Y of the object over and over
//but only does it till the end
listalabels[pbola].setLocation(listabolas[pbola].getPosX(), listabolas[pbola].getPosY());
}
}
Here is the function moverbola(), only copied one "if" so that the code doesn't look to big
private void moverBola(int pbola, JLabel[] listalabels) {
if (listabolas[pbola].getDireccion().equals("SE")) {
int pposX = listabolas[pbola].getPosX();
listabolas[pbola].setPosX(pposX + 1);
int pposY = listabolas[pbola].getPosY();
listabolas[pbola].setPosY(pposY + 1);
}

Swing is a single threaded framework. That is, all interactions with UI are expected to occur from within a single thread, known as the Event Dispatching Thread.
Any action that blocks this thread, will prevent the EDT from updating the screen or processing any new events.
Your while-loop is blocking the EDT, preventing it from painting any updates until after the while-loop is completed.
Take a look at Concurrency in Swing for more details.
There are a number of approaches you could take...
You could use a Thread, but this causes problems as you need to ensure that any changes you make to the UI are re-synced back to the EDT and this can become messy...
For example
You could use a javax.swing.Timer that ticks at a regular interval and you would update any internal parameters from within it's assigned ActionListener. Because the tick events occur within the EDT, it is save to update the screen from within it.
For example
You could use a SwingWorker to run the task in the background. It has methods for re-syncing updates back to the EDT, but might be a little over kill for your purposes...
Updated with a possible Timer example
Caveat- It is very hard to produce a reasonable example with only a code snippet, but, something like this might work
public void golpe(final int pbola, int pvelocidad, String pdireccion, final JLabel[] listalabels) throws InterruptedException{
listabolas[pbola].setVelocidad(pvelocidad);
listabolas[pbola].setDireccion(pdireccion);
Timer timer = new Timer(40, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (listabolas[pbola].getVelocidad() == 0) {
((Timer)evt.getSource()).stop();
} else {
moverBola(pbola, listalabels);
}
}
});
timer.setRepeats(true);
timer.start();
}

Related

Using Timer to repaint in the fixed time then continuing calculation

Currently, I am making a Java program for graph visualization Prim's algorithm in finding minimum spanning tree.
Here is the image of my program's output
while(condition){
//Find the min vertex and min edges
Vertex vertex = findMinVertex();
Edge[] edges = findMinEdges();
//Then, for each vertex and edges I found, I will change the color of
//them and pause the program for 3 seconds, so user can see how
//algorithm works.
repaintAndPause(3000);
}
.
.
private void repaintAndPause(int time){
long start = System.currentTimeMillis();
long end = start + speed;
//Here is the timer for repainting.
Timer timer = new Timer(speed, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e){
GraphPanel.this.repaint();
}
});
timer.setRepeats(false);
timer.setDelay(0);
timer.start();
//And here is for pausing the program, a while loop without any commands.
while(System.currentTimeMillis() < end){}
}
However, I don't know why but the program doesn't work. Yes, there are the pauses of program but, all the edges and vertices are just changed the color at the end of program. They aren't changed every 3 seconds.
Could someone please tell me where I did wrong?
Thank you and hope you have a nice day!
Could someone please tell me where I did wrong?
Yes. You are putting a busy-loop in the Event Dispatching Thread.
while(System.currentTimeMillis() < end){}
You code reads:
do some calculation (busy)
when done, post a "repaint" message, to redraw the panel when not busy
continue being very busy doing nothing for 3 seconds
continue being busy by repeating steps 1 through 4.
The Event Dispatching Thread never finishes processing the first "event" until the end of the algorithm, after the while (condition) loop finally finishes.
You want:
Timer timer = new Timer(speed, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
/* Code to perform one step of Prim's algorithm here */
/* Change edge/vertex colour for step */
/* Call timer.stop(), once done */
GraphPanel.this.repaint();
}
});
timer.setRepeats(true);
timer.setDelay(3000);
timer.start();
On every tick of the timer (once every 3 seconds), one step of the algorithm is performed.
Note this means that each step of the algorithm must run with any partial results stored into class members, so the the next step will be able to retrieve all the information it needs to continue. Stack variables can only be used inside one step; they cannot be used to hold inter-step values.
You could rework the algorithm to use a SwingWorker to run the calculation in its own background thread, and publish intermediate results when computed. The EDT could then repaint as intermediate results are produced. With a Thread#sleep() call, this background thread could delay production of intermediate results to once per 3 seconds.
Alternately, you could run the algorithm, and store multiple copies of the output, once for each 'step'. Then your Panel timer could simply show the output of the next step.

Looping through colours in a window

I'm a beginner in Java programming and have come across an issue (probably an easy one to solve).
I am experimenting with Java GUI and wish to create a window in which the colours of an array are cycled through until there are no more colours. I believe I can do this using a for loop and cycling through the array, however I do not know how to loop through the background colour.
Any help and explanation would be appreciated.
public void flashColor() {
Color [] color = { Color.red,Color.orange,Color.green };
int i = 0;
for(i=0;i<color.length;i--){
getContentPane().setBackground(Color(i));
}
}
This line tells me:
getContentPane().setBackground(Color(i));
that yours appears to be a Swing GUI (a key bit of information that you left out of your question!), and so you need to take Swing threading into consideration. Your current code will in fact loop through all the colors, but it will do so immediately, and on the Swing thread so that the GUI will have no way to paint any of the colors other than the last one. The solution: use a Swing Timer and not a for loop. Inside the timer advance an index int variable and use it to show the color.
Something like:
getContentPane().setBackground(colorArray[0]);
int delay = 1000; // for 1 second
Timer myTimer = new Timer(delay, new ActionListener() {
int index = 0;
public void actionPerformed(ActionEvent e) {
index++;
if (index >= colorArray.length) {
((Timer)e.getSource()).stop(); // stop the timer
} else {
getContentPane().setBackground(colorArray[index]);
}
}
});
myTimer.start();
The code has not been tested, and you'll want to read the Swing Timer tutorial for the details.
Note the key here is that yes you need to loop, and to pause (so that the color can be seen) but you need to do your looping and pausing in a thread thread is off of the Swing event dispatch thread (or EDT). Yes you could do this using a SwingWorker, but that is a way more difficult way to do this. It is far easier to use a Swing Timer to do this for you. Note that it uses a background thread invisibly for you.

How to wait for a specified time between parts of code in Java?

I have fairly simple question I didn't see properly answered anywhere.
I'm designing a Java applet using java.awt. What I'm trying to do is to have Java wait a few seconds between executing different parts of code in a method for a simple graphical animation.
So it goes like this:
runAnimation() {
// draw red shapes
// wait 2 seconds so the shapes remain visible
// set color of shapes to green and repaint
}
As suggested elsewhere, if I use something like
try {
// do first task
Thread.sleep(2000);
// do second task
} catch (InterruptedException e) {
}
the program only shows the results of the second task after waiting 2 seconds ie I never see the red shapes. I want to see the red shapes for two seconds and then have them set to blue and so on.
You don't say what GUI / graphics library you're using which is key information. If Swing or AWT, then use a Swing Timer to do your pausing. You should not use Thread.sleep(...) for this as you would put the GUI's event thread to sleep, causing the whole application to freeze.
e.g.,
someColor = Color.RED;
int delay = 2000;
repaint()
Timer swingTimer = new Timer(delay, new ActionListener() {
public void actionPerformed(ActionEvent e) {
someColor = Color.GREEN;
repaint();
}
});
swingTimer.setRepeats(false);
swingTimer.start();

JAVA Swing Gui Window Hangs

I am having an issue with SWING GUI or at least I think it is the swing gui.
Here is my main code file:
/**
*
*/
package com.tda.t2.ctas.slasher;
import javax.swing.SwingUtilities;
import com.tda.t2.ctas.slasher.gui.mainFrame;
import com.tda.t2.ctas.slasher.utils.MyCloseListener;
public class SLASHer {
public SLASHer () {
}
/**
* #param args
*/
public static void main(String[] args) {
//EventQueue.invokeLater(new Runnable() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ConfigData myconfig = new ConfigData();
try {
//TdaUrlHelper window = new TdaUrlHelper();
//window.tdaFrame.setVisible(true);
mainFrame tdaFrame = new mainFrame();
tdaFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Simple call to create the frame and open it. There are other files that I did not put here for space. But the problem that I have (and I have tried on several machines and operation systems) is that the buttons on the window seem to hang. I can select the window and click on the buttons and they highlight like they were hit but nothing happens. I have a tabbed plane and clicking on the other tabs also does nothing. Some times this last for about 15 seconds and other times it lasts several minutes. But it always eventually comes back and will respond to new input (ie it does not remember all the click around I did before it came back). The application overall is simple in that it sits waiting until a user does something before it does something so I am confused on why it seems to hang.
Any help would be appreciated.
Thanks
What is the offending code attach to the button that hangs? Check your console for exceptions, and put some System.out.println() statements at the top and bottom of that code. See if you see those print statements print out. Watch how long it takes for the one at the top to print and bottom one to print. If you see both statements then you know that whole block is executing, but if it takes a while to show the last statement you know you are hanging up the Swing thread (also known as EDT - event dispatch thread). Rule number one in Swing the UI can't repaint while it's executing your ActionListener.
In order to make a responsive UI you have to see the first and last statement appear on the console in under 10-100ms (visually almost instantaneous). If you really want to get fancy you can use System.currentTimeMillis() at the stop and bottom. Subtract the two values and println() it. That'll tell you exactly how long that listener ran for. If it's greater than 100ms you need to restructure your code by either improving your algorithm or off loading the long calculation on a thread (see this SwingWorker tutorial).
public void actionPerformed(ActionEvent event) {
System.out.println("Starting SomeProcess");
long start = System.currentTimeMillis();
// all your code belongs here
long duration = System.currentTimeMillis() - start;
System.out.printf("SomeProcess took %,d ms%n", duration );
}

How to change a JLabel's text in a loop without switching so fast the user can't see it?

I want to create a simple clock using Java. The code is so simple that I will give an example:
for(int i=0;i<=60;i++)
jLabel11.setText( Integer.toString(i) );
The problem is while I'm running my program the result didn't show each update in sequence.
It show only the 60 digit immediately, without showing the change from 1 to 2 to 3 ...
How can i fix this problem?
The problem is that changes to the UI should run on the event dispatch thread, but blocking this loop (and blocking the UI) will stop the screen from repainting. Instead, use a timer to perform regular updates, e.g.
Timer timer = new Timer();
ActionListener updater = new ActionListener()
{
int count;
public void actionPerformed(ActionEvent event) {
jLabel11.setText( Integer.toString(count++) );
if (count==60)
timer.stop();
}
}
timer.setDelay(100);
timer.addActionListener(updater);
timer.start();
See the Sun Tutorial - How to use Swing Timers.

Categories