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.
Related
Following situation:
I code a Domino game for Android. At the beginning of the game, if not a bot is the starting player, a user should pick two Dominos that get onto the board.
Overview of my non-working approach:
Definition of an empty ArrayList, call of a function that attaches Click Listeners on every Domino belong to the user followed by a while loop that does nothing, should just be the mechanism to wait until the user has picked two dominos. These dominos should be stored in the ArrayList(adding of the dominos to the ArrayList in FirstDominosPickerListener)
The code
In the activity:
ArrayList<Domino> starterDominos = new ArrayList<Domino>();
startingPlayer.chooseStartDominos(starterDominos);
the function:
public void chooseStartDominos(ArrayList<Domino> starterDominos){
///Every Domino gets a ClickListener
for (Domino domino : playerSet){
domino.setOnClickListener(new FirstDominosPickerListener( starterDominos));
}
//The idea is to wait until the user has picked two Dominos. With that loop, no UI at all shows up
while (starterDominos.size()<2){
Log.v(LOG_TAG," WAIT!!!!");
}
}
The problem is the while Loop. With the loop, no UI shows up, i get an empty white screen, altough the code runs. In logcat, i get infinite "Wait" messages. No idea why.
A second approach I've tried was to call a Timer task in the activity after that checks if two dominos were picked (through the size of the list) starterDominos = startingPlayer.chooseStartDominos(starterDominos);
I realized that couldn't work because that runs in another thread and because of that, it wasn't possible to access any part of the UI. But the mechanism to pick the dominos worked. UI showed up and run() ended after two dominos were picked through cancel().
So why does the while loop leads to that behavior? Is the whole approach wrong and if so what can I do that the app waits until the dominos were picked and then proceed
Your while loop is blocking the main UI thread so nothing can be drawn or updated on the screen. You need to set up a listener for when a user selects a domino, then proceed after a user has selected two dominos.
You can use a class variable in the activity class 'userDominoSelectCount' which can be a short integer field initialized to 0.
You can add the onClickListener for domino in the activity onCreate method itself:
domino.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
++userDominoSelectCount;
if(userDominoSelectCount == 2){
//initiate AI logic
userDominoSelectCount = 0;
}
}
});
The way you are doing will block the main thread as mentioned in other answer to the question. OnClicklisteners are meant to be run in event loop and ideally should not block UI.
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.
we are still working with the nasty robots and got another problem (after solving our package problem).
We have a robot which is running in a thread. He runs constantly forwards (move() method) and is checking if the currentDir variable has changed. If it has changed, he would call another method to get face the new direction.
Our problem is that we have to change the currentDir variable somehow. We want to do this by calling the setDir() method of our robot which is running in the thread.
This function is called after an event happened, triggered by a JButton.
But we can not manage to interrupt the thread to call this method.
Is it maybe possible to create a listener listening in the thread itself for a ActionEvent triggered by a JButton?
public void run()
{
//Infinite while-loop to check for the Direction of the robot
while(true)
{
if(currentDir != getDirection()) // if currentdir is not
{
if(currentDir == Direction.NORTH)
goNorth();
else if(currentDir == Direction.EAST)
goEast();
else if(currentDir == Direction.SOUTH)
goSouth();
else
goWest();
}
else
move();
}
}
You don't really need to set the direction from the same thread. If you set it from the UI thread in the listener, the thread should be able to just pick it up.
You might want to also make the direction variable volatile. http://www.javamex.com/tutorials/synchronization_volatile_typical_use.shtml
example: i got a button, if press it will call a function to fetch data from API to screen. but how can i stop calling the function if the user press again and the function is still running(Processing).
instead of hiding the button is there any way to handle it? do i need to use thread to handle it? to check if thread alive? i am not familiar with that. please give me some suggestion and example on how to handle it.
sorry for my bad english.
thanks.
Make a boolean that turns true when you press the button. When its true do the normal functions of the method. Then make it so when the person presses the button again the boolean turns false. When it is false make it do what you want to break out or return or do nothing.
If the function you are calling is synchronized, the you should not have any problem.
If the function is starts a thread, then you can do like this:
Thread mThrd = null;
public void func() {
if(mThrd!=null && mThrd.isRunning()) {
return;
}
mThrd = new Thread(/*the runnable that do the job*/);
mThrd.start();
}
If the function is a framework API that just "does something in the background", it might have some method to tell you that it is done or not, or you can check the result by some methods. Like:
public void func() {
if(checkDone()) {
return;
}
callFrameworkAPI();
}
when you call the function, add the following lines to your function, this will make the button unclickable after it has been clicked once.
Button b1 = findViewById(R.id.button_name);
b1.setClickable(false);
After the api fetch is done, probably the end of the function in your case, add the following lines, to make the button clickable again.
b1.setClickable(true);
I'm trying to accomplish something very simple. First, load my layout (main.xml). Then wait 1 second, modify an image, wait 1 second and modify it to a third image. (My end goal is more complex, of course, but I can't even get this to work).
Basically, I get a black screen when the app loads. It stays that way until all the waiting is over, then it shows the final image. Here's my code:
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageCard[0] = (ImageView)findViewById(R.id.imageView11);
Thread.sleep(1000);
ImageCard[0].setImageDrawable(getResources().getDrawable(R.drawable.secondimage));
Thread.sleep(1000);
ImageCard[0].setImageDrawable(getResources().getDrawable(R.drawable.thirdimage));
ImageCard[0] is the image I'm trying to change. It loads in main.xml and shows fine if I remove the rest of the code.
If I change the sleep time to 5000, it then takes 10 seconds before it finally comes away from the black screen and shows the third image. This is how I know it's not just loading slow, but that it's actually waiting.
It's like it's not running sequentially. I'm no java expert, so I'm assuming I'm doing something dumb...
Thanks for any help!
I think you are blocking the UI Thead. Try Handler.postDelayed on a static Handler object.
Ok heres your problem, you can never do a sleep(...) when you are in the UIThread. The UIThread is never suppose to be locked up, it causes a lot of very bad things to happen in android. But there is a very easy way around it, just get off the UIThread and hop back on it when you need to. Heres what i would recommend:
public void onCreate(...)
{
super.onCreate(...);
myActivity.setContentView(R.layout.main);
new Thread(this).start();
}
public void run()
{
try
{
changeLayout(R.layout.main2);
Thread.sleep(5000);
changeLayout(R.layout.main3);
Thread.sleep(10000)
changeLayout(R.layout.main4);
}catch(Exception e){}
}
public void changeLayout(int id)
{
this.id = id;
myActivity.post(new Runnable()
{
public void run()
{
myActivity.setContentView(id);
}
});
}
private int id;
Of course with this example your class must implement Runnable to work. Only the UIThread can access the UI, no other thread can. Thats why you have to hop on and off the UIThread. Hope this worked!
Try adding ImageCard[0].invalidate() when you want it to draw.
I think Hovercraft Full of Eels is pointing you in the right direction. Essentially, you're not doing any multi-threading, you're telling the main thread to wait which means that it never completes the drawing. I'm not sure about Android, but Swing uses double-buffering by default (to avoid screen flashes), but that means that what is drawn, is actually drawn on to a buffer, not the window itself which is why you don't see anything. You could try disabling the double buffering (which Android is likely using) but that could cause other issues.
You might want to actually do multi-threading, or, I'm sure Android likely has a Timer component. If it does, I'd suggest you use it over Thread.sleep or actual multi-threading. Using a Timer you can have it fire an event after one second. That event will execute the other code.
do you have that code in constructor or in init() function? if yes, draw just the first picture and the Thread.sleep() function move after the place which the constructor or the init() function was called from.
then call repaint() function or something.