Timer problems with swing GUI components - java

This snippet of code essentially reveals the back side of the cards when clicked. The showFace function sets the icon and text and therefore implying the front of the card. Light gray background is the back. If a non matching card is clicked, I first intend to showFace for a brief moment ( 2 seconds) than revert to the "back side of the card." However, upon clicking a non matching card, the icon and text flashes instantaneously and reverts to its gray background.
Tried changing the 2000 milliseconds to something higher but no avail. Any help is appreciated.
else if (currentMode == 1){
//matched cards
if(checkCards(currentCard, names)){
showFace();
currentMode = 0;
currentCard = "";
deafTo(this);
}
//else non match, still checking mode
else{
showFace();
var timer: Timer = null;
val action = new ActionListener(){
override def actionPerformed(event : ActionEvent){
icon = null;
text = "";
background = Color.DARK_GRAY;
timer.stop();
}
};
timer = new Timer (2000, action);
timer.setInitialDelay(0);
timer.start();
}
}
def showFace()={
text = names;
horizontalTextPosition = Alignment.Center;
verticalTextPosition = Alignment.Bottom;
background = Color.WHITE;
val icons = new ImageIcon(path);
val newIc = icons.getImage();
val newIcons = newIc.getScaledInstance(100, 75,
java.awt.Image.SCALE_SMOOTH);
icon = new ImageIcon(newIcons);
repaint();
}

This is because you set an initial delay of 2000ms in the constructor
timer = new Timer(2000, action)
But then you overwrite it to 0ms by:
timer.setInitialDelay(0);
Remove this line and you should be good.
You can check here Swing Timer API.
And see some examples here.

Javadoc http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html
This class does not offer real-time guarantees: it schedules tasks using the Object.wait(long) method.
Java 5.0 introduced the java.util.concurrent package and one of the concurrency utilities therein is the ScheduledThreadPoolExecutor which is a thread pool for repeatedly executing tasks at a given rate or delay. It is effectively a more versatile replacement for the Timer/TimerTask combination, as it allows multiple service threads, accepts various time units, and doesn't require subclassing TimerTask (just implement Runnable). Configuring ScheduledThreadPoolExecutor with one thread makes it equivalent to Timer.

Related

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.

Refreshing JTable step by step in Java

I am doing a Pacman game using A* algorithm in Java. I searched a lot of questions. I found a solution for one step. But I want to refresh my table in while block and my solution is just refreshing JTable according to the last step(just showing the result) in while(calculated all steps). But I want to refresh and show Pacman's places(location) step by step in while block. It has to look like Pacmans are moving. But I couldn't. My codes is below:
btnStartGame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//randomly placement of Pacmans
table_1.setValueAt(yellowPacman, locationyellowX, locationyellowY);
...calculating heuristics
//after calculation
newXYellow =locationyellowX;
newYYellow =locationyellowY+1;
nodeYellow = 10 * newXYellow + newYYellow;
while(heuristics != zero){
...enemy pacmans' movement
//after enemy pacmans' movement calculating yellow pacman's movement
if((newXYellow>=0 && newXYellow<10 && newYYellow>=0 && newYYellow<10) && !wallList.contains(nodeYellow)){
//calculate heuristic again
manhattanDistance[0][0] = Math.abs(newXYellow-locationblackX[0])+
Math.abs(newYYellow-locationblackX[0]);
manhattanDistance[0][1] = Math.abs(newXYellow-locationblackX[1])+
Math.abs(newYYellow-locationblackX[1]);
manhattanDistance[0][2] = Math.abs(newXYellow-locationblackX[2])+
Math.abs(newYYellow-locationblackX[2]);
fyellow[0] = manhattanDistance[0][0] + manhattanDistance[0][1] + manhattanDistance[0][2];
selectedNodeXYellow = newXYellow;
selectedNodeYYellow = newYYellow;
timer2.start();//updated
while(delay != 0)
delay--;
delay = 4000;
locationyellowX = selectedNodeXYellow;
locationyellowY = selectedNodeYYellow;
nodeYellow = 10 * selectedNodeXYellow+ selectedNodeYYellow;
timer3.start();//updated
while(delay != 0)
delay--;
delay = 10000;
}//ending if
}//ending while
}
}//ending action
timer2 = new Timer(ONE_SECOND, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
table_1.setValueAt(null, locationyellowX, locationyellowY);//I wanted to delete old moves
timer2.stop();
}
});
timer3 = new Timer(ONE_SECOND, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
table_1.setValueAt(yellowIcon, locationyellowX, locationyellowY);//here I want to show each moves step by step in while block
timer3.stop();
}
});
UPDATE 1 :
Delay was just an idea. Maybe algorithm is calculated too quickly and timers cannot be fired. But it didn't work and also does not timer suppose to be fired at each one second? still I've seen the last values of JTable.
I suspect your main issue here is that you need to understand how the various threads in a Java GUI application work. Specifically, if you have code executing in the event dispatch thread then there will be no updates to the UI while that code is executing. In your case you are making multiple updates to a JTable and then returning control to the display which will then show the last value.
The solution here is to introduce a timer element that executes each step of your algorithm in each tick of the timer and then returns control to display the result. Check the javax.swing.Timer class for details. I also suggest you read the sections 'concurrency in Swing' and 'How to use Swing Timers' in the Java tutorials.

Screen Capture in separate thread making Java application slow/unresponsive

I'm working on an application that records the users screen, webcam and microphone whilst he/she is performing certain activities. It will be used for research purposes. The application has been successfully tested on Windows, but on Mac OS X (Maverick with Java 7.0.45) the application becomes slow and unresponsive when recording is started.
This is why I find this difficult to comprehend:
The recording is done in a separate thread, so how could it influence the responsiveness of another thread? Especially as after each run either Thread.yield() or Thread.sleep(...) are called.
Logs show that whilst attempting to record at 15 FPS, the resulting frame rate was 2 FPS. So it seems the code that does the capturing of a single frame might be too slow. But why then does it work fine on Windows?
Just a quick note: the application was successfully tested by tons of users on Windows, but I only got to test it on a single Mac. However, that one was just formatted and got a clean install of OS X Maverick, Java (and Netbeans).
Below you will find the code that records the screen and writes it to a video using Xuggler. The code for recording the webcam is similar, and I'd doubt recording the audio has anything to do with it. My question is:
What might be the cause of the application becoming unresponsive?, and
How could the code be made more efficient and so improve FPS?
IMediaWriter writer = ToolFactory.makeWriter(file.getAbsolutePath());
Dimension size = Globals.sessionFrame.getBounds().getSize();
Rectangle screenRect;
BufferedImage capture;
BufferedImage mousePointImg;
writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_H264, size.width, size.height);
int i = 0;
while (stop == false) {
// Get mouse cursor to draw over screen image.
PointerInfo mousePointer = MouseInfo.getPointerInfo();
Point mousePoint = mousePointer.getLocation();
Point screenPoint = new Point((int) (mousePoint.getX() -
Globals.sessionFrame.getBounds().getX()), (int) (mousePoint.getY() -
Globals.sessionFrame.getBounds().getY()));
// Get the screen image.
try {
screenRect = new Rectangle(Globals.sessionFrame.getBounds());
capture = new Robot().createScreenCapture(screenRect);
} catch ( ... ) { ... }
// Convert and resize the screen image.
BufferedImage image = ConverterFactory.convertToType(capture,
BufferedImage.TYPE_3BYTE_BGR);
IConverter converter = ConverterFactory.createConverter(image,
IPixelFormat.Type.YUV420P);
// Draw the mouse cursor if necessary.
if (mouseWithinScreen()) {
Graphics g = image.getGraphics();
g.drawImage(mousePointImg, (int) screenPoint.getX(),
(int) screenPoint.getY(), null);
}
// Prepare the frame.
IVideoPicture frame = converter.toPicture(image, (System.currentTimeMillis() -
startTimeMillis()) * 1000);
frame.setKeyFrame(i % (getDesiredFPS() * getDesiredKeyframeSec()) == 0);
// Write to the video
writer.encodeVideo(0, frame);
// Delay the next capture if we are at the desired FPS.
try {
if (atDesiredFPS()) {
Thread.yield();
} else {
Thread.sleep(1000 / getDesiredFPS());
}
} catch ( ... ) { ... }
i++;
}
writer.close();
There are several architectural issues that I can see in your code:
First if you want to execute something at a fixed rate, use the ScheduledThreadPoolExecutor.scheduleAtFixedRate(...) function. It will make your entire delay code part obsolete as well as ensuring that certain OS timing issues will not interfere with your scheduling.
Then to make things faster you need to take your code apart a bit. As far as I can see you have 3 tasks: the capture, the mouse-drawing/conversion and the stream writing. If you put the capture part in a scheduled Runnable, the conversion into multi-parallel execution as Callables into an Executor, and then in a 3rd thread take the results from a result list and write it into the stream, you can fully utilize multi-cores.
Pseudocode:
Global declarations (or hand them over to the various classes):
final static Executor converterExecutor = Executors.newFixedThreadPoolExecutor(Runtime.getRuntime().availableProcessors());
final static LinkedBlockingQueue<Future<IVideoPicture>> imageQueue = new LinkedBlockingQueue<>();
// ...
Capture Runnable (scheduled at fixed rate):
capture = captureScreen();
final Converter converter = new Converter(capture);
final Future<IVideoPicture> conversionResult = converterExecutor.submit(converter);
imageQueue.offer(conversionResult); // returns false if queue is full
Conversion Callable:
class Converter implements Callable<IVideoPicture> {
// ... variables and constructor
public IVideoPicture call() {
return convert(this.image);
}
}
Writer Runnable:
IVideoPicture frame;
while (this.done == false) {
frame = imageQueue.get();
writer.encodeVideo(0, frame);
}
You can ensure that the imageQueue does not overflow with images to render if the CPU is too slow by limiting the size of this queue, see the constructor of LinkedBlockingQueue.

Making moving motion with labels using threads in 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();
}

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