This question already has an answer here:
Swing, Java and multithreading, and coloring buttons
(1 answer)
Closed 8 years ago.
I´ve been trying to make a multiple choice question game using swing elements, I am just using a JTextArea to show the questions and four JButtons for the options.
I would like that every time the user answer a question the correct answer is shown by changing the background color of the JButton with the correct answer.
I am using a MVC design pattern so each time the user clicks the options JButtons the actionPerformed method calls a method in the interface that sets the background color of the JButton, sleeps the thread for one second and then it sets the background to the default color.
Everything seems to be right however when a run the program the graphic interface doesn't change the background color, although you can see the thread sleep.
If someone could help me solve this problem i would be very grateful, I include the code of all the described methods.
public void showCorrectAnswer (int index)
{
//JButtons array
options[index].setBackground(Color.green);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
options[index].setBackground(defaultColor);
}
ActionPerformed code of option buttons:
public void actionPerformed(ActionEvent e)
{
JButton source = (JButton) e.getSource();
int index =controller.getTheModel().getIndexWereTheRightAnswerIs();
controller.getTheMainView().showCorrectAnswer(index);
}
Using Thread.sleep from within the context of the Event Dispatching Thread is preventing the EDT from processing new paint requests (the changing of the background color).
Swing is also not thread safe, this means that you should only modify the UI from the context of the EDT.
Instead, you should consider using a javax.swing.Timer instead. This will allow you to schedule a callback at some time in the future and, when triggered, take action that will be executed from within the context of the EDT.
Take a look at Concurrency in Swing and How to Use Swing Timers for more details
What I would do is set up a non-repeating timer with a one second delay, set the background color of the button and start the timer. When the timer triggers, reset the background color of the button
Also, depending on the look and feel, setting the background color of the button may not have any (or only a small) effect, just so you know...
Related
When the actionPerformed method is invoked I would like it to display the desired icon on the first button, delay for 1 second and then display the icon on the second button. The icons always display simultaneously? Not sure how to correct this.
#Override public void actionPerformed(ActionEvent e)
{
btnTest1.setIcon(img2);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
btnTest2.setIcon(img2);
}
I'm assuming this is for JavaFX / Java Swing. I'm not too familiar with it, but I believe the threads aren't working is because there are concurrency rules related to using threads in swing apps. I've had similar issues and wrote a question about how to delay something using threads. I found sources for using a timer object. It might be better to implement the timer by doing:
import javax.swing.Timer;
I'm sure other more advanced users may give more detail. This is maybe another option. Oracle might help too:
https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
The buttons' icons are set with setIcon, but that doesn't mean they are painted immediately. Both icons will only be painted after you return from your actionPerformed method. What you need to do is set the icon for the first button, then use Timer (see zOrigin_'s answer) and after the timer elapses, set the second button's icon.
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.
This question already has answers here:
get data from GUI every 10s java
(2 answers)
Closed 5 years ago.
trying to develop a simple GUI application in NetBeans.
I want to create some kind of a GUI logging system, to write the current action that's being performed by the application, into a TextArea.
As a simple example, I created a JFrame form which contains only 2 objects: a "Start" button and a TextArea.
When the "Start" button is pressed, it invokes some kind of a lengthy method that should take some time (say, 10 seconds) to complete running, and while this method is running, I want to append text to the TextArea from withing this lengthy method (and of course I want the TextArea to be immediately updated).
My problem is that I cannot find the proper way of doing that. Anyway I tried doing this, when I press on the "Start" button, the application freezes for 10 seconds, without updating the TextArea like I wanted. Only when the method finishes, I see the update to the TextArea.
Here's a sample code:
private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {
try {
for (int i = 0; i < 10; i++) {
textArea.setText(i + "\n");
Thread.sleep(1000);
}
} catch (Exception e) {}
}
Don't use Thread.sleep(...) in a listener. All listener code is executed on the Event Dispatch Thread (EDT). The GUI won't be able repaint itself until the loop is finished executing.
The solution is to use a separate Thread for the long running task. One way to do this is to use a SwingWorkder. Once the code is executing on a separate Thread you can use Thread.sleep(...) (if necessary).
Read the section from the Swing tutorial on Concurrency for more information on the EDT and on using a SwingWorker. The tutorial contains a working example to get you started.
I think you need to create a new Thread and execute the 10 second code right there. Otherwise, the GUI will freeze instead
I'm creating a board game using a GUI and JFrames/JPanels where you can play against the computer. I have a method called showPieces() which updates board GUI by changing the image icons on an array of buttons (which are laid out in a grid format). Once the icons have been updated the revalidate() and repaint() methods to update the GUI.
The showPieces() method has a parameter that needs to be passed to it every time it is called.
The main issue I'm having is I want the human to make a move, update the GUI, wait 1 second, the computer makes it's move and then loop until someone wins.
My basic code is the following:
do{
human.makeMove();
gui.showPieces(data);
try {
Thread.sleep(1000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
computer.makeMove()
gui.showPieces(data);
}while(playing);
This cause the issue where when the human player makes their move, the GUI will freeze for one second and then after the delay, both moves are made at the same time.
I hope it makes sense, but I'm a novice with Java and may have to look more into threading as I don't understand it well enough.
Thread.sleep() is done on the Event Dispatch Thread which will lock the GUI.
So If you need to wait for a specific amount of time, don't sleep in the event dispatch thread. Instead, use a timer.
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
}
};
new Timer(delay, taskPerformer).start();
As with most all similar Swing questions, you're putting your entire Swing GUI to sleep by calling Thread.sleep(...) on the GUI's event thread (the EDT or Event Dispatch Thread), and when during this period the GUI will not be able to update its images or interact with the user whatsoever. The solution here is not to use Thread.sleep(...) but rather to use a Swing Timer to cause your 1 second delay.
Swing Timer Tutorial.
I'm creating a board game using a GUI and JFrames/JPanels where you can play against the computer. I have a method called showPieces() which updates board GUI by changing the image icons on an array of buttons (which are laid out in a grid format). Once the icons have been updated the revalidate() and repaint() methods to update the GUI.
The showPieces() method has a parameter that needs to be passed to it every time it is called.
The main issue I'm having is I want the human to make a move, update the GUI, wait 1 second, the computer makes it's move and then loop until someone wins.
My basic code is the following:
do{
human.makeMove();
gui.showPieces(data);
try {
Thread.sleep(1000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
computer.makeMove()
gui.showPieces(data);
}while(playing);
This cause the issue where when the human player makes their move, the GUI will freeze for one second and then after the delay, both moves are made at the same time.
I hope it makes sense, but I'm a novice with Java and may have to look more into threading as I don't understand it well enough.
Thread.sleep() is done on the Event Dispatch Thread which will lock the GUI.
So If you need to wait for a specific amount of time, don't sleep in the event dispatch thread. Instead, use a timer.
int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
}
};
new Timer(delay, taskPerformer).start();
As with most all similar Swing questions, you're putting your entire Swing GUI to sleep by calling Thread.sleep(...) on the GUI's event thread (the EDT or Event Dispatch Thread), and when during this period the GUI will not be able to update its images or interact with the user whatsoever. The solution here is not to use Thread.sleep(...) but rather to use a Swing Timer to cause your 1 second delay.
Swing Timer Tutorial.