Text box with data validation - java

I want to ask the user for their gender. I want to create a text box that they can answer the question in. The do-while loop is to ensure they answer with either "boy" or "girl". There are no errors but it won't run.
Note I have all the necessary imports...
public class Culminating_JavaFX extends Application {
String gender;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
#Override
public void start(Stage primaryStage) throws Exception {
GridPane grid = new GridPane();
TextField textField = new TextField ();
do
{
textField.setPromptText("Are you a boy or a girl?");
textField.setText("");
gender = br.readLine().toLowerCase();
}
while (!(gender.equals("boy")) && !(gender.equals("girl")));
GridPane.setConstraints(textField, 0, 1);
grid.getChildren().add(textField);
}
public static void main(String [] args) {
launch(args);
}
}

public class Culminating_JavaFX extends Application {
private GridPane grid = new GridPane();
private TextField textField = new TextField();
private Label label = new Label("Are you boy or girl?");
private Button btn;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
btn = new Button();
btn.setText("Answer");
// set action listener -> runs when button is pressed
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// process the form
process();
}
});
// set constraints
GridPane.setConstraints(textField, 0, 0);
GridPane.setConstraints(label, 0, 1);
GridPane.setConstraints(btn, 0, 2);
// add components to grid
grid.getChildren().add(textField);
grid.getChildren().add(label);
grid.getChildren().add(btn);
// show scene
primaryStage.setScene(new Scene(grid, 300, 250));
primaryStage.show();
}
private void process() {
// get text
String text = textField.getText();
// process text
if (text.equals("boy")) {
label.setText("You are a boy.");
} else if (text.equals("girl")) {
label.setText("You are a girl.");
}
}}
image of required imports
I wrote a short example, please check it above. Your program goes into do-while loop and stays there. It never gets to the point where it would draw the window and components. That's why it doesn't run.

On a side note, make sure from now on you try to keep your logic code and your graphical user interface code as separate as possible. Never try to cram everything into the GUI class.
Next thing is that the general idea of GUI's is that their logic can't be tied up in loops before being ran. When your program runs and calls start(), it will proceed downwards and execute code and needs to hit a line called window.show();. This displays the window to the user. If your program is stuck in that loop above, it won't ever be able to even display the GUI to the user and thus won't work.
Instead, rethink how your program will work. Since the user needs to select boy or girl, why not use a ChoiceBox for that, or better yet, a RadioButton. Have the user select the choice they want, then perhaps have a Button for them to click to submit or have the ChoiceBox or RadioButton listen for changes by calling:
yourRadioButton.setOnAction(e ->
{
/*
* Set the Boy Girl value here by calling
* yourRadioButton.getValue()
*/
}

Related

JavaFX: Button event still executes without having to press the button for a second time

my problem is the following:
I have a JavaFX application with a Button called "bindB";
Button bindB = new Button("None");
bindB.setOnAction(event -> {
bindB.setText("...");
BindKey.bindKey(scene, bindB);
});
with the text "None". Is this button pressed, his text first changes to "..."
and by then calling the method "BindKey.bindKey();", the text will change to the
name of the key, the user is pressing on his keyboard.
This is the code of the method "BindKey.bindKey();":
public static void bindKey(Scene scene, Button bindB){
scene.setOnKeyPressed(event -> {
bindB.setText(String.valueOf(event.getCode()));
});
}
As you can see, in the args of the method we give the button "bindB", so that the method knows
what button to change the name of, aswell as the current scene.
This code does work, but the problem is, that even after the button was
pressed, and its text has already be changed, the text still changes to the name of different
keys if you press them afterwards WITHOUT having to press the button a second time.
I thought that you had to end the "setOnAction" event by calling
event.consume();
but that didnt work...
So how do I make the buttons text only change, if the button has actually been pressed a second or third time?
Otherwise, the task which the button performs is toggled by EVERY key because technically
every key is the toggle key as the task reads the name of the button to know what key is for toggling.
Full code example:
Main class:
public class Main {
// Initialize GUI
public static void main(String[] args) {
GUI gui = new GUI();
gui.run();
}
}
GUI class:
public class GUI extends Application {
public void run() {
launch();
}
#Override
public void start(Stage window) throws Exception {
// When closing Window
window.setOnCloseRequest(event -> {
exitApplication(window);
});
// GridPane
GridPane grid = new GridPane();
grid.setPadding(new Insets(10, 10, 10,10));
grid.setVgap(15);
grid.setHgap(30);
// Scene
Scene scene = new Scene(grid, 200, 200);
window.setScene(scene);
// Bind Button
Button bindB = new Button("None");
GridPane.setConstraints(bindB, 1, 1);
bindB.setOnAction(event -> {
bindB.setText("...");
BindKey.bindKey(scene, bindB);
});
// Add to Grid
grid.getChildren().addAll(bindB);
// Show Window
window.show();
}
// Provide a clean exit
private void exitApplication(Stage window){
window.close();
Platform.exit();
System.exit(0);
}
}
BindKey class:
public class BindKey {
// Changes Buttons text
public static void bindKey(Scene scene, Button bindB){
scene.setOnKeyPressed(event -> {
bindB.setText(String.valueOf(event.getCode()));
});
}
}
I am not to 100% sure if this is the problem, but I think the only thing you have to do is the following:
scene.setOnKeyPressed(event -> {
bindB.setText(String.valueOf(event.getCode()));
scene.setOnKeyPressed(null);
});
}
You just have to remove the Key-Listener from the scene after you set the text. Because otherwise it will listen for keys the entire time.

Cannot add CSS classes to my JavaFX Label

I am making a simple todolist app. Here is a watered-down version of it:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
ListView<Label> todoListView = new ListView();
Label doneTodo = new Label ("This todo is meant to be finished and struck through");
doneTodo.getStyleClass().add("done"); // Add the "done" class to this to-do
Label undoneTodo = new Label("This todo is meant to be undone and therefore isn't struck through");
// Add both to-dos to the listview
addTodo(doneTodo, todoListView);
addTodo(undoneTodo, todoListView);
// Set the listview as the scene, and add the stylesheet
Scene scene = new Scene(todoListView, 600, 550);
scene.getStylesheets().add(getClass().getResource("styles.css").toExternalForm());
primaryStage.setTitle("Label not taking on Strikethrough");
primaryStage.setScene(scene);
primaryStage.show();
}
// Adds the to-do (in this case just a simple Label) to the listview
private static void addTodo(Label todo, ListView<Label> todoList) {
todoList.getItems().add(todo);
}
public static void main(String[] args) {
launch(args);
}
}
Here is my CSS class:
.done {
-fx-strikethrough: true;
}
When I run the code, the -fx-strikethrough property does not show up on my Label. Note that although this is a simplified version of my app, the issue remains the same: The text inside the JavaFX Label is not being struck through.
Again, sorry for any inadequacies in my question. I am fairly new to Stack Overflow!
Thanks in advance.
The CSS rule should apply to the text node under the label node:
.done .text {
-fx-strikethrough: true;
}

Is it possible to return a variable in javaFX from a close method? Is there a more efficient way to do this?

I would like to run a method that would close a pop up window when an answer is selected or the window is closed manually and then return the value selected (a boolean). Unfortunately, I do not know how I would retreive the data because I initially call the method that displays the query, not the close method.
I have tried many different things but when I try to use a close method I am unable to retrieve the data returned from it. Otherwise, the data returns before the user is able to mutate it. Neither result achieves my goal
This is my method that creates the box. I currently just close the window instead of closing via an alternate closing method.
public class ConfirmBox
{
static boolean answer;
public static boolean display(String title, String question) {
Stage window = new Stage();
//Block events to other windows
window.initModality(Modality.APPLICATION_MODAL);
window.setTitle(title);
window.setMinWidth(250);
//LabelQ
Label label = new Label();
label.setText(question);
//YesBox
Button yesB= new Button("Yes");
yesB.getStyleClass().add("button-green");
yesB.setOnAction(e -> {
answer=true;
window.close();
});
//NoBox
Button noB= new Button("No");
noB.getStyleClass().add("button-red");
yesB.setOnAction(e -> {
answer=false;
window.close();
});
window.setOnCloseRequest(e ->{
e.consume();
window.close();
});
VBox layout = new VBox(10);
layout.getChildren().addAll(label, yesB, noB);
layout.setAlignment(Pos.CENTER);
//Display window and wait for it to be closed before returning
Scene scene = new Scene(layout, 800, 200);
scene.getStylesheets().add("styles.css");
window.setScene(scene);
window.showAndWait();
return answer;
}
}
This is my method that runs everything thus far.
public class Main extends Application
{
Stage window;
String gender;
String name;
public static void main (String[] args){
launch (args);
}
public void start(Stage primaryStage) throws Exception{
window= primaryStage;
window.setTitle("Pokemon Gray");
GridPane grid= new GridPane();
grid.setPadding(new Insets(10, 10, 10, 10));
grid.setVgap(8);
grid.setHgap(10);
// Name Label
Label nameLabel= new Label("UserName");
GridPane.setConstraints(nameLabel,0, 0);
//Name input
TextField nameInput = new TextField();
GridPane.setConstraints(nameInput,1, 0);
//GenderLabel
Label genderLabel= new Label("Gender");
GridPane.setConstraints(genderLabel,0, 1);
//Gender Boy
Button boySelect= new Button("Boy");
boySelect.getStyleClass().add("button-blue");
GridPane.setConstraints(boySelect, 1, 1);
boySelect.setOnAction(e-> gender="Male");
//Gender Girl
Button girlSelect= new Button("Girl");
girlSelect.getStyleClass().add("button-red");
GridPane.setConstraints(girlSelect, 2, 1);
girlSelect.setOnAction(e-> gender="Female");
//Login
Button saveName= new Button("Save Name");
GridPane.setConstraints(saveName, 1, 2);
saveName.setOnAction( e -> {
boolean valid =verifyText(nameInput.getText());
if ((valid)&&((gender == "Male")||(gender=="Female"))){
String qStr= "Are you sure your name is "+nameInput.getText()+" and you are a "+gender+"?";
boolean confirmed= ConfirmBox.display("Confirmation", qStr );
if (confirmed == true){
name= nameInput.getText();
}
}
else{
ErrorBox.display("Error", "You must enter a name less than 20 characters long and a gender");
}
});
grid.getChildren().addAll(nameLabel, nameInput, genderLabel, boySelect, girlSelect, saveName);
Scene scene= new Scene(grid, 1000, 1000);
scene.getStylesheets().add("styles.css");
window.setScene(scene);
window.show();
}
public boolean verifyText(String text){
boolean valid;
if ((text.length() > 0) && (text.length() <= 20)){
valid= true;
}
else{
valid=false;
}
return valid;
}
}
I want to be able to run a seperate method that closes it and returns the answer boolean in the ConfirmBox to the Main method. But currently it returns null because it returns immediately.
Edit: It should be noted I currently do not have a close method. I deleted my previous one because it caused many issues.
I think that you can't do that, you need to do another screen like:
If(button.getResult==yes){"charge yesscreen")else{"charge no screen"}
The controllers for differents screens can't interectionate with another screens, you only can call the differents screens from to a controller but you can't pass values with hims, try do something like this I work with javafx with this mentality all screens are independents and you only invoce the differents screens . you can do something like this:
class first screen{
is a girl?
is a charizar?
is a x)
if(isgirl && is a x...){
call screen x
}else if(ismen&& is a z..){
call screen z
}
{

How to save/store variables after clicking a button in javafx

I am super new to JavaFX, with some knowledge of Java tho.
My target is to develop a desktop broad game.
It should ask players for certain options and determine how the game would proceed (like voting, selection rooms, etc)
It works perfectly in Java using Scanner but not in JavaFX;
Whenever I click a button, it only affect the variable in the block.
I do need these chosen options to be used later to support the game logic.
Please help.
Updated - I move the if statement into the action block but it still not set scene to welcome.
public class Main extends Application{
Button startGame,howTOPlay, viewRoomButton, viewItemListButton;
List<Scene> playersenes = new ArrayList<>();
Scene welcomeScene, playerRedScene, playerYellowScene, playerBlueScene, playerGreenScene, playerBrownScene, playerBlackScene;
Stage mainWindow;
static int numberOfPlayers;
final static int WIDTH =800;
final static int HEIGHT=600;
;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
//mainWidow setup
mainWindow = primaryStage;
mainWindow.setTitle("Mall of Horror");
//startgameScene
List<Integer> numberOfPlayersOptions = new ArrayList<>();
numberOfPlayersOptions.add(4);
numberOfPlayersOptions.add(5);
numberOfPlayersOptions.add(6);
GameBroad gameBroad=new GameBroad(1);
PlayersChoice playersChoice = new PlayersChoice();
startGame = new Button();
startGame.setText("Start Game");
startGame.setOnAction(event -> {
//numberwindow.display is a new stage with a method return a static int
//gamebroad is class with models, which require the number of players to support its logic.
gameBroad.setPlayersNumber(NumberWindow.display(numberOfPlayersOptions, "please select how many players"));
//playerChoise is a class, ok is default fault boolean. set Ok is method to set the ok boolean to true;
playersChoice.setOk();
mainWindow.setScene(welcomeScene);
if (playersChoice.isOk()){//it stop working here
//welcomeScene;
Label welcome = new Label();
welcome.textProperty().setValue("Welcome players " + gameBroad.getPlayersNumber() );
Button ok1 = new Button("OK");
ok1.setOnAction(event1 -> {
mainWindow.setScene(playerRedScene);
});
VBox welcomePlayerslayout = new VBox();
welcomePlayerslayout.getChildren().addAll(welcome,ok1);
welcomeScene = new Scene(welcomePlayerslayout, WIDTH, HEIGHT);
//playerRedScene;
viewRoomButton = new Button();
viewRoomButton.setText("Rooms");
viewItemListButton = new Button();
viewItemListButton.setText("Items");
VBox playerRedLayout = new VBox();
playerRedLayout.getChildren().addAll(viewRoomButton,viewItemListButton);
playerRedScene = new Scene(playerRedLayout, 800,600);
}
System.out.println(playersChoice.isOk()); //it shows true here;
});
howTOPlay = new Button();
howTOPlay.setText("How to Play");
VBox firstlayout = new VBox();
firstlayout.getChildren().addAll(startGame, howTOPlay);
Scene firstscene = new Scene(firstlayout, WIDTH, HEIGHT);
primaryStage.setScene(firstscene);
mainWindow.show();
}
}
if (playersChoice.isOk()){//it stop working here
It did not stop working there. It didn't start to work. It defaults to false until you click startGame, and the action does not check again if the choice is okay.
Therefore, you need to setup your welcome actions within the start button action, which only runs after you click the button.
In the current code, that if statement is ran before the button click despite the code having been written below the action. In other words, GUI programming does not explicitly run top to bottom.
Your next issue is that you have mainWindow.setScene(welcomeScene); before welcomeScene = new Scene(welcomePlayerslayout, WIDTH, HEIGHT);

Taking input from textField and displaying it in textArea

I have having trouble getting my program to take the user input from textField and displaying it in textArea. The program I'm making is a Stack/Queue program. It has a textField that a user inputs a number into. Then there is a button that takes the input and displays it in the textArea as a Stack(FILO).
Edit 1:
I am able to move the user input into the textArea now but, whenever I add a second input it just replaces the old input with the new instead of showing the list. I am supposed to use a toString method to show the whole list? Where do I need to put the toString method if I need it?
TLDR, How do I take input from textField and display it in textArea?
This is my main class.
TextField text = new TextField();
TextArea textArea = new TextArea("Text Area");
public class StackQueue extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Stack myStack = new Stack();
Button btAdd = new Button("Add");
Button btDel = new Button("Delete");
Button btClear = new Button("Clear");
BorderPane bpane = new BorderPane();
text.setPrefWidth(50);
text.setAlignment(Pos.CENTER_LEFT);
text.setText("Label");
text.clear();
textArea.setPrefColumnCount(1);
textArea.setPrefRowCount(10);
textArea.clear();
HBox hBox = new HBox();
hBox.getChildren().addAll(btAdd, btDel, btClear);
bpane.setTop(hBox);
bpane.setCenter(text);
bpane.setBottom(textArea);
Scene scene = new Scene(bpane, 500, 250);
stage.setTitle("Stack Example");
stage.setScene(scene);
stage.show();
EventHandler<ActionEvent> addEvent = event -> add();
EventHandler<ActionEvent> delEvent = event -> del();
btAdd.setOnAction(addEvent);
btDel.setOnAction(delEvent);
public void add()
{
textArea.setText(text.getText(x));
}
public void del()
{
}
}
public static void main(String[] args)
{
launch(args);
}
}
This is the Stack class.
public class Stack<E>
{
public String status = "String";
public ArrayList<E> arrayList;
public Stack()
{
arrayList = new ArrayList(10);
}
public void add(String x)
{
arrayList.add(0, (E) x);
}
//public String del
{
}
public void Clear()
{
}
}
You have included add() and del() function inside the start() function. You need to move them outside of start() function and inside of your StackQueue class.
After doing that the variables text and textArea should be created outside of start() function because the method add() and del() are trying to get the value of text and textArea variables.
Finally, you should implement the logic to handle addition and deletion of elements inside add() and del() methods.
Paste the following code in StackQueue.java file. I didn't implement the deletion functionality and you need to tweak the add() method too. I hope now you will be able to solve it.
I added a string which will get the old value of text field and append that old value when further addition is done along with the new value
public class StackQueue extends Application {
TextField text = new TextField();
TextArea textArea = new TextArea();
String oldText;
#Override
public void start(Stage stage) throws Exception
{
Stack myStack = new Stack();
Button btAdd = new Button("Add");
Button btDel = new Button("Delete");
Button btClear = new Button("Clear");
BorderPane bpane = new BorderPane();
text.setPrefWidth(50);
text.setAlignment(Pos.CENTER_LEFT);
text.setText("Label");
text.clear();
textArea= new TextArea("Text Area");
textArea.setPrefColumnCount(1);
textArea.setPrefRowCount(10);
textArea.clear();
oldText = text.getText();
HBox hBox = new HBox();
hBox.getChildren().addAll(btAdd, btDel, btClear);
bpane.setTop(hBox);
bpane.setCenter(text);
bpane.setBottom(textArea);
Scene scene = new Scene(bpane, 500, 250);
stage.setTitle("Stack Example");
stage.setScene(scene);
stage.show();
EventHandler<ActionEvent> delEvent = event -> del();
btAdd.setOnAction( e -> {
textArea.setText(oldText + text.getText());
oldText = oldText + text.getText() +"\n";
});
btDel.setOnAction(delEvent);
}
public void del()
{
}
public static void main(String[] args)
{
launch(args);
}
}

Categories

Resources