JavaFX - Create Loop of Logic that Pauses for User-Prompt Windows - java

As part of my efforts to familiarize myself with the MVC model, I am attempting to write a program that loops through a set of code calculations while occasionally pausing to prompt the user for input with custom windows created in JavaFX, using that input to continue the calculations until a certain result is reached to break the loop. The idea is that for each window, the user selects an option, the window closes, and then the logic continues until the next user input is needed. Then the next window opens and the process continues. Based on what the user inputs, the choices included in the next window can change. For my starting example, the window has four buttons with the numbers 1-4 and prompts the user to choose a number. I boiled down my code to something really basic:
public class LogicLoop()
{
public static AtomicInteger CHOICE; //Global variable to act as the user's current choice, as there is only ever one choice made at a time
public static boolean loopDone = false;
public static void main(String [] args)
{
new Start().startLoop(); //Calls the class that extends Application to call the launch() command. Since launch() can only be called once, it needs to be outside the loop
logicLoop();
}
public void logicLoop()
{
while(!loopDone)
{
Chooser chooser = new Chooser();
chooser.show();
int choice = CHOICE.get();
CHOICE = null;
doSomething(choice);
}
public doSomething(int choice)
{
//Set some other variables to modify how the next window will look
//Potentially set loopDone to true;
}
}
}
And then my Chooser class:
public class Chooser()
{
public int show()
{
Stage newStage = new Stage();
createWindow(newStage); //method that sets up window based on global variables and calls show() on newStage. Each button in the window will close the stage. The CHOICE value will also be set based on the user's input
}
}
The window created by createWindow() has buttons with the following handle() method:
public void handle(ActionEvent event) {
CHOICE = new AtomicInteger(btn.getValue()); //I made my own Button class that has a value variable and a getter() for it
Stage stage = (Stage) btn.getScene().getWindow();
stage.close();
}
The issue I'm facing is that when my code goes to execute, the logic doesn't wait for the user's input before continuing right past the show() method. So what happens is the code starts the loop, and immediately brings up the first window. At the same time, a NullPointerException is thrown because my logic is already trying to call CHOICE.get() before the user even has time to input any value. So after choosing a button and closing the first window, nothing else happens.
So far I've tried making use of the showAndWait() method in my createWindow() method, but it doesn't appear to make any difference. I've tried calling the wait() command after chooser.show(), but it just adds a delay and then I see the same results. Based on information I've been able to find on Stack Overflow, I've seen a lot of recommendation to use the Platform.runLater() method, but I can't see how it would be effective here. If the GUI runs later, the logic will still just stampede ahead without it. I need the logic loop to pause until the window closes, which seems to be what showAndWait() is designed to do. What confuses me the most is a statement I came across while researching an answer that said that implementing a basic MVC framework does not require multithreading and that it is not advisable for a beginner to make use of it. At this stage, I'm not certain how that's possible.
What am I missing here?

Related

Interface management eclipse

I al reading a code that I did not create and I have some trouble to understand how it is working and especially how action event ( like a click) are managed ?
So far I am undertanding that it creates a the first window will all buttons and boxes and the main end with a setVisible(true); and my window appears.
Then is ask my some file locations and I click on a button to go to the second window.
What I would like to understand it is how in java we managed this click event for the second action ? I mean I understand the use of button addActionListener the first time but my understanding ends with the second event (=I click on the button and it brings me to the second window and do the calculation) i.e. where/ how in the code this is handle and goes a scond time to the functions.
Knowing that at the end of the main I have some functions starting with
InterfaceDynamics.cardSwitch() and this function managed all events that can occur
public static void cardSwitch(final String _buttonKey, final String _Key, final JPanel _cardPanel,
Another related question (I guess related) it is the use of
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Main();
which I really do not undertand (even if I already google it).
Sorry if I am not clear and for my bad understanding of java and window, Swing, Frame management and really thanks for any help.
Regards

How do action events work with players' turns, need help showing which card the user played before the computer shows what card it played

Im creating an uno game and it is almost fully functional and i'm using javaFX to create it. It is Computer vs User and the problem is that when a user clicks on a card button, the middle card is supposed to be replaced with that card and then the computer goes, however what ends up happening is that the computer goes right away and so you only see the computer's card played in the middle. I am sure this has something to do with how i structured my code specifically the action event pertaining to the button clicked. However, since this is my first ever java GUI and i am fairly new to java i am struggling to understand how to structure it so that i am able to show the user's move. Also due to this, i am unable to implement a skip card even though i have tried using a boolean and creating another method i think the main problem lies within how the main gameloop and the actionevent inside is set up.
This method is called and it checks for a button click and then gets the index of the button in the player's arraylist/hand/ The boolean was my attempt at implementing a skip card but what kept happening is the computer would always play right after the user's move when a skip card was played.
public void gameLoop(){
for(int i =0; i<buttonList.size();i++){
buttonList.get(i).setOnAction((ActionEvent)->{
indexOfHandButton = buttonList.indexOf((Button)ActionEvent.getSource());
humanMakeMove();
if(!isReverseTurn()) {
computerMakeMove();
}
});
}
}
This method used the index given from the gameloop actionevent and makes the actual move in the backend. It then clears the hbox containing the users hands and calls showhumanHand which fills it up with the updated cards and similarily with the middle card. The if statements to try and implement the skip cards have not worked, i have also tried creating a new action even inside the if statement and creating a method or recursively calling humanMakeMove but of course the index will be the same and will cause an error.
public void humanMakeMove() {
String result = human.makeMove(game, theDeck, indexOfHandButton, computer);
if(result.equals("skip")){
setReverseTurn(true);
}
hbHumanHandBtn.getChildren().clear();
hbMiddleCard.getChildren().remove(middle);
middle = generateMiddleCard();
hbMiddleCard.getChildren().add(middle);
showHumanHand();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>" + buttonList);
System.out.println(result);
if (middleCard.getType() != null) {
if (middleCard.getType().equals("skip") && isReverseTurn()) {
System.out.println(isReverseTurn());
gameLoop();
setReverseTurn(false);
}
}
}
So my main question is how can i restructure this or add something that allows for the user's card to show in the middle before the computer goes right away, i have tried a timer/sleep method too. And my skip card doesnt work but i think that has to do with how i set up my action listener which is messing up two problems. Thank you for reading this and let me know if you have any input!

Wait for 2 click events until proceed doesn't work

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.

How to get a method to run only after another method runs to completion

I'm making a simple game involving lots of GUIs. The first time a user plays, I want the program to first open GameStart();. In there, the user learns the story, picks a class, and sets a name. A boolean variable gameStarted will be marked as true when the user clicks the last button in the GameStart class.
Now, any time the user opens the game again and loads a save file, gameStarted is true so it will skip the intro stuff.
My problem is that as is, the program doesn't execute anything after the first if statement. Below is what I have.
public static void main(String[] args){
if (!gameStarted){
new GameStart();
//use setters
}
if(gameStarted){
//do the rest of the game
}
}
If in between the if statements I add:
while(!gameStarted){
sysout("waiting")
}
it works, but obviously the console is flooded with waitings and that's bad. A blank while loop doesn't work. moving my setters from the if statement to the while loop doesn't work unless I have the sysout in there as well.
Any ideas?

How to get a MouseListener to stop being in control

I am writing a trivia/quiz program in which the user answers questions and his/her answers are judged as correct or incorrect based on the screen coordinates they have clicked. For a clean design, I wish to load the questions using an external function, then attach a MouseListener to the screen object afterward.
My code currently resembles that given below.
void main() {
screen = new QuizScreen();
//load data for question
screen.awaitAnswer();
}
public class QuizScreen implements MouseListener{
//...variables...
//...blank methods for MousePressed, MouseReleased, etc...
public void mouseClicked(MouseEvent me){
//check if answer is right
}
public void awaitAnswer(){
QuizScreen.addMouseListener(this);
}
}
This code works fine for loading, allowing play of, and checking the answer to a single question. However, after the first question has been loaded, I want to be able to repeat the process -- to load ANOTHER (and possibly many more) questions -- by adding a loop to the "main" function. This is currently not possible, since I don't know how to get the MouseListener to stop listening to the user's clicks and return from awaitAnswer() to main().
How do I stop getting the MouseListener to listen to the user? How would I get out of an event-driven section of my code and back to an automatically executing section?
Remove the awaitAnswer method.
Create a (default) constructor for QuizScreen with statement addMouseListener(this);.
From your mouseClicked function, just execute a callback to your main program to create and destroy the QuizScreen

Categories

Resources