I'm trying to code a simple game in Java. The basic structure is a single JFrame with different JPanels that I add/remove at different times. At startup, there is a JPanel that's a basic menu (start game, high scores, etc). Once the "Start" button is pressed it switches to a level selector panel with three buttons to select the difficult level of the game. Once any of the three buttons is pressed, it switches to another panel that will displays a three second countdown, then the actual game. All three buttons call the same method, just with a different difficulty value passed in.
I have all the separate pieces working fine, but I'm having troubles with the transition from the level selection panel to the countdown. If I don't use threads the screen freezes on button press and does not switch to the new panel. I've tried messing around with threads, but I don't know that much about them and have only had limited success (I've got it so it will successfully switch some of the time, but not consistently).
In terms of code, in the level selection panel I have something like this listening for button clicks:
private class ButtonClickedListener implements ActionListener {
public void actionPerformed(ActionEvent evt) {
gui.newLevel(1);
}
}
where in place of just gui.newLevel(1) I've messed around with starting new threads and calling the method from them.
The newLevel() method look like:
getContentPane().removeAll();
levelPanel = new LevelPanel(levelNum, this);
add(levelPanel);
validate();
levelPanel.start();
I use very similar code when switching from the start menu JPanel to the level selector panel (again, with an ActionListener on the buttons), which works just fine.
LevelPanel's start() method initializes values for the new JPanel and displays the countdown on screen (currently with the following code, although I messed with putting something like this in the newLevel() method instead) before displaying the actual game:
try {
Thread.sleep(1000);
//update countdown number
validate();
repaint();
Thread.sleep(1000);
//update countdown number
validate();
repaint();
Thread.sleep(1000);
//update countdown number
validate();
repaint();
} catch (Exception e) {
System.out.println(e);
}
//start game
I would really appreciate any help getting this code to work, and I'm pretty sure some sort of threading is the way to go but I'm not quite sure where/how. Any suggestions and/or code samples would be great!
Thanks in advance!
EDIT: I ended up rewriting the countdown using a timer instead of Thread.sleep(), which fixed part of the problem and the rest of it I eventually figured out and was entirely unrelated to GUI stuff, which is why I didn't think to check it in the first place.
never really never use Thread.sleep(1000); during EDT, this code caused freeze on GUI is un_resposible, untill a new event invoke EDT or mouse hover over can alive this container too
1) there are two ways how to dealy any event(s) in the Swing GUI, by implements
Swing Timer
delaying by using Thread.sleep(1000); in the SwingWorker
The layout and painting must be done in EDT. Use SwingUtilities.invokeAndWait to call the validate() and repaint()
You can start some code with a time delay using TimerTask:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
invokeLater(); // This starts after [delay] ms
// and - if given - will run every [period] ms.
}
}, delay, period);
You could solve your problem with this, though it won't be a pretty solution.
// edit: (see comments) you should synchronize accesses to the gui properly, else it will give you errors.
Related
So, I have an object that extends JPanel and displays dots in a matrix via paintComponent. The dots of the matrix can move, disappear or multiply given certain conditions, and I want to show their evolution over time automatically like so:
for(int i = 0; i < 100; ++i){
matrix = calculateNextMatrix(); //Calculate possible movements, deaths or births of dots
myGraphic.updateMatrix(matrix); //Pass new dots to the JPanel object
myGraphic.repaint(); //Draw new dots
Thread.sleep(100); //Wait 0.1 seconds for next iteration (yes, this should be in a
//try-catch)
}
However, I only get drawn the last iteration after the loop is finished, and all the previous calls to repaint() are basically ignored. If I do the iterations only one at a time (for example, via a manual button press), I have no problem.
Is there any way to get multiple, periodic repaint calls automatically?
I had a simile problem with JComponent in my library and I found a solution with swing timer, I reported the java description of timer
In general, we recommend using Swing timers rather than general-purpose timers for GUI-related tasks because Swing timers all share the same, pre-existing timer thread and the GUI-related task automatically executes on the event-dispatch thread. However, you might use a general-purpose timer if you don't plan on touching the GUI from the timer, or need to perform lengthy processing.
You can use Swing timers in two ways:
To perform a task once, after a delay.
For example, the tool tip manager uses Swing timers to determine when to show a tool tip and when to hide it.
To perform a task repeatedly.
For example, you might perform animation or update a component that displays progress toward a goal.
I think you are in one of this cases.
Without a minimal example reproducible, I can use the my code.
You should create the Swing action listener, like this:
public class UpdateComponentListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
count += 10;
timeLabel.setText(count + "");
//The label call repaint
//in your app you should be call the repaint
//In your cases
/*
matrix = calculateNextMatrix(); //Calculate possible movements, deaths or births of dots
myGraphic.updateMatrix(matrix); //Pass new dots to the JPanel object
myGraphic.repaint();
*/
}
}
The timer constructor get in input the delay and the action listener, so you can build your timer, with this code:
Timer timer = new Timer(1000, new UpdateComponentListener());
timer.start();
You can stop, restart your timer, so you should be set how propriety the timer.
The GUI example:
I wrote the post and after I see the #camickr comment. I post the answer because my work is finished but, the comment answered your question.
I hope to have to build a food example
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 need a timer for a game I am building and what it basically does is fire up an event that moves and object a square every second when I hit play. Now either I let the game take its course(the game finishes or the object moves out of bounds) or press play once again, the timer seems to be triggering the object to move faster than previously and so on, going faster and faster every time I restart the time.
private void playButtonMouseClicked(java.awt.event.MouseEvent evt) {
/*code*/
timer = new Timer(timerSpeed, new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
/*code that ends with something that calls timer.stop()*/
}
}
});
if(timer.isRunning()) //in case I don't let the game stop the timer
timer.stop();
timer.start();
}
I checked with timer.getDelay() and the delay doesn't change, it stays the same, but I can see the arrow moving faster and faster every time. I'm using jPanels and a label with and icon to display the grid and the moving object.
Any ideas?
but I can see the arrow moving faster and faster every time.
This tells me you have multiple Timers executing.
Your current code creates a new Timer every time the button is clicked.
The timer.isRunning() check will never be true because you just created a new Timer which will not be running since you haven't started it yet.
So your old Timer may still be running but because you no longer have a reference to it, you can't stop it.
The solution:
Don't create a new Timer object every time you click the button. The Timer object should be created in the constructor of your class. Then you just start/stop the Timer as required
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.
A small app containing a BufferedImage uses the Timer class for animation. Everything works, but not as expected.
Sometimes the system struggles to draw the animation, as though it is draining system resources (especially after installing the JRE), which makes the animation redraw at abnormally low speeds. Other times it works as expected.
What could cause this?
Thank you!
Switch to java.util.Timer, javax.swing.Timer seems to be better suited to actions that are called every minute or second as opposed to java.util.Timer which is far better adapted to tens of calls per second.
Sorry everyone..my bad!
The class I am using is javax.swing.Timer!
Here is part of the code (timer implementation -- not the method timer calls):
Timer t = new javax.swing.Timer(10, new ActionListener(){
public void actionPerformed(ActionEvent ev){
//This little if/step statement actually decides if
//the ellipses I have on screen will be colored all together
//or step by step
if(app.flagStep == false){
for (int i = 0; i<list.size(); i++){
drawBuffer(i);
}
}
else{
if(app.stepBut.isEnabled()){
app.stepBut.setEnabled(false);
}
drawBuffer(app.myStep);
}
}
});