In my program, a the graphics on my screen are supposed to move across the screen. I have a loop that calls the draw function(the draw function is display.draw()), but whenever the amount of times the loop runs is greater than one, the display doesn't update after each time like it should. Instead, it waits until the loop finishes to update the display.
below is the refreshing function that only apparently runs at the end.
public void refresh()
{
myPanel.removeAll();
myPanel.add(display.draw());
myPanel.validate();
myPanel.repaint();
}
And here's the loop. I added a 1 second sleep after each iteration to make sure it just wasn't moving faster than I could see.
for(int i = 0; i < 2; i++)
{
myGraphics.rearrange();
this.refresh();
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
}
myGraphics.rearrange() simply changes the values of the variables which the drawing function uses,
changing the x and y variables for the positions of all the objects.
What is happening that it's not updating?
You're calling Thread.sleep(...) in a Swing program on the Swing event thread. What this does is put the entire application to sleep and so is not something that you should be doing. Instead use a Swing Timer to drive your animation.
For example:
Similar question 1
Similar question 2
Similar question 3
For more specific help, consider posting more code, preferably an mcve.
Related
I have a for loop that changes the location of a JLabel in a JLayeredPane layout.
c.setVisible(true);
jLayeredPane.moveToFront(c);
for (int i = 0; i < 1000; ++i) {
c.setBounds(i, 500, 94, 136);
System.out.println(c.getLocation());
try {
Thread.sleep(2);
} catch (Exception e) {
}
}
This method is referencing to jLayeredPane, which is accessed from another class. It does indeed update the x value of the JLabel c, yet it does not show it on the screen.
What do I have to do to make it update in real time? I need this to run in order, not simultaneous to the next part of the program, thus I suppose multi-threading is disallowed.
What do I have to do to make it update in real time?
Don't use Thread.sleep(). This will cause the Event Dispatch Thread (EDT) to sleep, which means the GUI can't repaint itself until the entire loop is finished executing.
For animation you need to use a Swing Timer
I need this to run in order, not simultaneous to the next part of the program
When the Timer fires the required number of times you then stop the Timer and invoke a method containing the rest of your code.
Also, you should not be hardcoding "1000" as the loop control. You have no idea what the resolution of the screen will be when code is executed on different screens. You can use the Toolkit class and the getScreenSize() methods to get the appropriate dimension to use based on your actual requirement.
I am having troubles with programming a game called "Coup" and to explain what the problem is, i need to briefly explain what the game is about. Coup is a card game where players try to eliminate each other and be the last player left. To do this, players can choose a number of actions but they can also lie to other players. In this game, other players can call "bullshit" or block another players action. Because of this, i need to make Response windows which will let other players respond with a challenge, a block or do nothing. The result of the action is then dependent on the responses. For example, a player tries to get foreign aid. I can decide to block his action or to let him continue. There are consequences if i block but that isnt the problem here.
The real problem is this: I want to give all my players a chance to give a response (Block or do nothing) via a JFrame and I use a while loop to wait for all players responses. However, this while loop doesnt do anything except keep the method from progressing since the result depends on players reactions. With the while loop, the JFrame I constructed appears white and doesnt contain the two buttons i made. At this point i can even press the close button and it wont respond due to the while loop I made which is dependent on my responseless window. Is there anyway to fix this?
if (turnCount == players[currentPlayerNum].getPlayerNum()){
for(int i=0; i<players.length;i++){
//If it is not the players turn and they have one or two lives, make response window
if (players[i].getPlayerNum() != turnCount){
if (players[i].getLives() != 0){
//foreignAidBlock constructs the response window
players[i].foreignAidBlock(turnCount);
}
else{
//Not applicable since out of game/not in game
players[i].setResponse("NA");
}
}
else{
//Not applicable since out of game/not in game
players[i].setResponse("NA");
}
}
//Idea: PAUSE TILL RESPONSES COME IN
while(players[0].getResponse() != null || players[1].getResponse() != null || players[2].getResponse() != null || players[3].getResponse() != null)
{
System.out.println(players[0].getResponse());
System.out.println(players[1].getResponse());
System.out.println(players[2].getResponse());
System.out.println(players[3].getResponse());
}
The result i get from running this part of the code is:
"NA
null
NA
NA"
continuously. I use a null to represent a player that hasnt answered yet. At the end of the method, I reset all of my players abilities back to null.
All my response window will do is change the response of the player from null to "B" or "N". But without access to the buttons I cannot do this. Does anybody have any tips on how to use something to "pause" my thread besides using a while loop?
As Abdul Fatir mentioned, it is because the UI thread is being blocked.
I would however not reccomend directly messing with threads. There is a SwingWorker class exactly for this scenario and it is reccommended you use this.
For more info check this blog article - Swing Worker Example
You can also find some useful info in the following SO question - How do I use SwingWorker in Java
Here is quick use example from the official javadoc:
Say we want to find the "Meaning of Life" and display the result in a JLabel.
final JLabel label;
class MeaningOfLifeFinder extends SwingWorker<String, Object> {
#Override
public String doInBackground() {
return findTheMeaningOfLife();
}
#Override
protected void done() {
try {
label.setText(get());
} catch (Exception ignore) {
}
}
}
(new MeaningOfLifeFinder()).execute();
The while loop is blocking your UI Thread. Perform your while loop checks in a different Thread.
Thread t = new Thread(new Runnable(){...});
t.start();
This way your UI won't be blocked and controls will remain responsive.
jf is a JFrame I'm trying to move a pixel in every 200 milliseconds. I created this method so I ciould pause the software for 200 milliseconds before cntinuing. millis and millisn are static longs.
public static void waitsec() {
millis =System.currentTimeMillis();
millisn =System.currentTimeMillis();
while (millisn<(millis+200)){
millisn=System.currentTimeMillis();
}
}
the following part is the part where I'm trying to make my JPanel (jp) to move slowly 50 pixels when a button is being pressed:
public void actionPerformed(ActionEvent h){
if (h.getSource() == button){
for (int i = 0; i <50; ++i){
waitsec();
out.println ("" + i);//I'm checkinf if the waitsec() is working OK
x +=1;
jp.setLocation(x, 0);
totalGUI.repaint();
jp.setVisible(true);//setting visible so I could focus on it
jp.requestFocusInWindow (); //suspicious part
jp.requestFocus ();
}}
}
The results of running this program are:
The numbers appear in the console one after another with 200 mmillis between them as expected.
The JPanel is not moving all the way once the numbers stop appearing (the program is done running). and if I try to minimize and maximize the window it doesn't show up till the program is done running as if the program has no focus at all...
why doesn't it focus although I had set it visible and focused it?
A number of things...
Firstly, you are blocking the Event Dispatching Thread, preventing it from processing any new events, including repaint events. This will make your application appear as it has hung, because essentially, it has.
Secondly, instead of rolling your waitSec method, you should be taking advantage of the available API functionality, for example, instead of trying to loop until a time period has passed, which while consume CPU cycles, you should use Thread.sleep instead.
Having said that though, you should NEVER sleep within the context of the EDT.
Instead, you should use something like a javax.swing.Timer which can be configured to raise an event on a regular bases. The benefit of this is it raises the event within the context of the EDT, making it safe to update the UI from within (unlike making your own Thread for example)
Take a look at Concurrency in Swing and How to use Swing Timers for more details
Thirdly, JPanel is not focusable by default, so calling requestFocusInWindow is not likely to have any effect
Fourthly, by default, Swing makes use of layout managers, so you may actually be struggling against this as well
I am learning java at the moment and trying to make different features and systems. Right now I am trying to make a really simple particle system, but I have problem.
public void eDelay()
{
try
{
Thread.sleep(17);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void engine()
{
int i = 0;
while (i < particles.size())
{
Particle a = (Particle) particles.get(i);
eDelay();
a.move();
i = i + 1;
}
}
public void actionPerformed(ActionEvent e)
{
engine();
repaint();
}
This is a part of my code where the particles suppose to move. It works fine and they do move, but I want them to move one after another one with a delay(17). However, they move all at once and not one after another.
(particles) is an arrayList with 50 elements in it, each element containst a position for a particle.
(a.move()) is just a movement method where particle moves up.
Don't worry for the rest of the code, the problem is in this part.
Graphics, positioning of the particles, movement of the particles, and other things work fine.
Going to make my comment an answer:
"Don't worry for the rest of the code, the problem is in this part. - Graphics, positioning of the particles, movement of the particles, and other things work fine."`
How can you say this when you know what the cause of your problem is? You could be creating a Swing application (which is part of the rest of the code) and calling Thread.sleep(...) on the event thread. So make no assumptions, tell us all of the story, show more pertinent code, and let's help you solve this.
Edit: I now see that this is in fact a Swing application and so that's likely your problem, although you don't show us where the Thread.sleep is called.Calling Thread.sleep(...) puts the thread that calls it asleep, and if this is the Swing event thread (or EDT), it will put your entire application to sleep -- not a good thing to do. So don't call Thread.sleep on the event thread and use a Swing Timer instead. The tutorials will show you how.
And of course again, don't make any assumptions.
You should call repaint in the engine() loop instead of actionPerformed().
Ok guys, this is actually a bit weird but I just rewrote the engine class again into a for loop and it works.
public void engine()
{
goingcrazy = goingcrazy + gameTimer.getDelay();
for(int i = 0; i < particles.size(); i++)
{
if (goingcrazy > 1000*i)
{
Particle a = (Particle) particles.get(i);
a.move();
}
}
}
I already posted a link for the full code so if you are interested you just need to change the old engine class with the one I just posted.
I'm currently making a game of Reversi for my programming class and I wanted to try and implement a computer into the game. I got this working successfully, but the computer makes their move instantly so you can't see how your move worked.
I tried solving this by using the following method:
public void wait (int n) {
long t0, t1;
t0 = System.currentTimeMillis();
do {
t1 = System.currentTimeMillis();
} while ((t1-t0) < n);
}
I then called this method after the player made their move, right before it called my computerAI() method.
However, it didn't work quite right and it seems like it hit the wait before it changes the colors of the board, because the player clicks, the background changes to the default light gray, and then after it waits a second, it performs the color changes of your move and the computers.
Anyone have any suggestions for fixing this?
Use:
Thread.sleep(5000);
This causes the current thread to sleep for 5 seconds.
You may need not only change button's color property, but also call its .repaint() or even .update() method often enough, e.g. every 100 ms. That is, you need to make the button actually redraw itself on the screen when you need it, not when the system determines it has time to render the accumulated changes.