This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 7 years ago.
I am trying to have my program break out of a while loop when a button on the gui is pressed.
I have a thread which launches the GUI thread and the waits until an apply button is pressed.
Here is the code:
public void run() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
// Wait until apply button clicked and set team
while(true) {
applyClicked = gui.getApplyClicked();
if (applyClicked == true) {
teamYellow = gui.getTeam();
break;
}
}
However even when I click apply and the applyClicked becomes true within the GUI it does not execute that if statement.
However if I add a print line underneath the while true it works ok.
I also debugged it running line by line and the variables set correctly and it works.
Why doesn't this work when I don't have a println? Is it something to do with threads?
Thanks
You're executing a busy-wait loop, which will I guess take all of your cpu power.
You should instead add an actionListener on your apply-button and do your stuff in the actionPerformed method.
This may not be the answer you are looking for exactly, but just in case, define applyClicked outside the loop and declare the loop as while(!applyClicked) so that the break is not needed, because if applyClicked is true, the loop will exit on its own. If that still doesn't work, run the new code with the debugger. This may or may not work, it's just a suggestion.
Related
I've made an infinite while loop that checks if a boolean is ever changed(I have a button in JFrame that make a false boolean true). However, even though I'm checking every tick, it only works if I print out the variable.
I'm pretty sure that the program doesnt update the variable unless I print it. Does anyone have any suggestions?
Code:
while (100 == 100) {
System.out.println(panelVar.getGen() == false);
boolean make = panelVar.getGen();
//System.out.println(make);
if (make != false) {
System.out.println(sentenceMaker(minLength, wordAmt, sourceTxt));
//panelVar.setGen(false);
}
}
}
GUIs are never supposed to run infinite loops on the main thread. This makes them lock-up, and will not respond, which might explain why your variable is not showing up.
You should use callbacks like ActionListener to notify external widgets of changes. You can also use AtomicBoolean for multi-threaded access
Otherwise, you are seeing race-conditions and should be running that loop in a separate Thread
Then, in my main file, I have a loop constantly waiting and checking if the boolean got updated.
You should not have a loop in your main file.
Instead you define a method like setMake(Boolean make) in you main file
When I click on the button the listener updates a boolean in my JFrame file.
So instead of updating the boolean directly, you invoke the setMake(…). Then in the setMake(….) method you change the state of the Boolean variable and do any special processing.
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.
tf is a JTextField.
Expected flow of execution:
The control is not supposed to move out of the first loop until something is entered in the JTextField named tf .
Second while loop should only run after the control moves out of the first one.
while(true)
{
if((!tf.getText().equals("")))
{
p.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
String name=tf.getText();
System.out.println("Hello "+name+",\nWelcome to Guess the number Game");
}
});
break;
}
else if (tf.getText().equals(""))
{
p.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
p.setSelected(false);
}
});
continue;
}
} //while end
while(true)
{ st="game on";
System.out.println(st);
if(!st.equals(""))
{
gamer3 game1=new gamer3();
Thread nt =new Thread(game1);
nt.start();
break;
}
Problems:
Second while loop is getting executed first. game on got printed.
As soon as I enter something into tf ,the code inside second while loop gets executed. Why is the control moving to second while loop as soon as I enter something into tf? Second while loop is not even dependent on tf.
I don't even need to press enter after entering something into tf. How is the entered value being recognized before pressing enter ?
Main issue:
Why is the second loop getting executed first?
According to the general flow of control, the control has to remain in the first loop until it encounters a break statement. Why is this not being followed here?
The control moves back to the previous loop when I press the start button.
Control never enters the else if in first while loop.
Note:
Second while loop gets executed only after I enter something into tf. And as soon as I press the Start Button first while loop gets executed.
Without a runnable example, it's difficult to ascertain what an out-of-context snippet of code might or might not do
I "suspect" you have an uncontrolled thread which is inspect the state of the field which is triggering actions which you aren't prepared for - Swing is not thread safe and you should not be monitoring or modify the state from outside the context of the EDT, remember, Swing (like most GUIs) is event driven.
Normally you would use either a DocumentListener to get real time feedback or an ActionListener so you can be notified when the user presses the Enter button (or presses another button on the UI)
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.
This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 7 years ago.
I am using the javax.swing packages to construct a gui, and have a while loop running forever with an if statement inside, to see if a button has been pressed. For some reason unbeknownst to me, this code only works if I print to the console inside the while loop.
Here is the algorithm structure:
while(true){
System.out.println(" ");
if (startOver && playPressed) {//set to true on JButton press
//do stuff
}
}
Possibly this is some sort of threading issue? Has anyone ever encountered such a problem before? Is there a method of waiting for a JButton to be pressed that doesn't involve an infinite while loop?
Thanks in advance!
Swing is event-based. You're not supposed to have infinite loops waiting for a button to be pressed. The loop is implemented by Swing internally. What you're supposed to do is to add an action listener to the event, which will be called by the button when it's clicked:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("The button has been clicked!");
// do stuff
}
}
This is fundamental stuff when dealing with Swing. You should read the swing tutorial.
Any infinite loop in the swing event dispatch thread will freeze the GUI forever.
The only way I was able to overcome this problem without an infinite loop was by creating a new thread for the "//do stuff" portion of the algorithm.
very strange, and I still don't understand why I had to print to console to make it work within the while loop.