I have been following an online tutorial on how to use JavaFX to create Java Gui programs.
This is one of the programs I made following using the tutorials. I decided to add a counter to the command line which would display the number of orders as well as the customers choices, although I was able to get this working the counter feature looks inefficient.
I feel adding another class to just add the orderNumber variable was wrong.
Is there any advice on streamlining this code?
Also what could I do to output the orderNumber after the Order?
public class Main extends Application {
private class Order {
public int orderNumber = 0;
}
Stage window;
Button button;
public static void main(String[] args) {
launch(args);
}
#Override
public void start (Stage primaryStage) throws Exception {
Order Number = new Order();
window = primaryStage;
window.setTitle("Luke's Sandwich's");
//Check Box's
CheckBox box1 = new CheckBox("cheese");
CheckBox box2 = new CheckBox("Bacon");
CheckBox box3 = new CheckBox("Tuna");
CheckBox box4 = new CheckBox("Tomatoes");
box1.setSelected(true);
//button
button = new Button("Order Now");
button.setOnAction(e -> {
Number.orderNumber++;
System.out.println("order: " + Number.orderNumber);
handleOptions(box1,box2,box3,box4);
});
VBox layout = new VBox(10);
layout.setPadding(new Insets(20));
layout.getChildren().addAll(box1,box2,box3,box4,button);
Scene scene = new Scene(layout,300,250);
window.setScene(scene);
window.show();
}
//Handle checkbox options
public void handleOptions (CheckBox box1,CheckBox box2,CheckBox box3,CheckBox box4){
String message = "user order:\n";
if(box1.isSelected())
message += "cheese\n";
if(box2.isSelected())
message += "bacon\n";
if(box3.isSelected())
message += "tuna\n";
if(box4.isSelected())
message += "tomatoes\n";
System.out.println(message);
}
}
Related
I have a JavaFX Application with many UI-Elements like Buttons, Sliders, TextFields and so on. I have a certain group of UI-Elements that I want the user to be able to change but only after he confirmed once, that he is sure he wants to change them. Any attempted change to any of those elements should be discarded, if the user does not confirm that he knows what he's doing.
I've made a very simple mockup.
public class App extends Application {
private Label label;
boolean changeConfirmed = false;
#Override
public void start(Stage stage) {
BorderPane pane = new BorderPane();
VBox container = new VBox();
Button button = new Button("Something");
Slider slider = new Slider(0,1,0.5);
TextField textField = new TextField();
label = new Label("Empty");
// Here should be the code I'm asking for
container.getChildren().addAll(button,slider,textField);
pane.setRight(container);
pane.setCenter(label);
Scene scene = new Scene(pane,400,300);
stage.setTitle("Alert Test");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
private void handle(String string) {
label.setText(string);
}
private boolean changeConfirmed(){
if(changeConfirmed) {
return true;
}
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirm Change");
alert.setHeaderText("A change occurred.");
alert.setContentText("Do you really want to change the value?");
Optional<ButtonType> buttonType = alert.showAndWait();
if(buttonType.isPresent() && buttonType.get().equals(ButtonType.OK)) {
changeConfirmed = true;
return true;
}
return false;
}
}
I want that, as long as the boolean changeConfirmed is false, any attempted change to any of the UI elements is interrupted by the changeConfirmed()-Method. Once the method returned true, the boolean is true and no further confirmation is needed (it would otherwise become very tiresome to confirm all changes for every UI-Element). The boolean changeConfirmed is made false again at a later time in the program and not relevant here.
What is absolut important to me is that the value of the property doesn't change before the confirmation has been passed.
I've tried using ChangeListeners (obviously) but to my knowledge, the value of the property has already been changed when the listener is executed. So the Alert comes to late (I might be wrong here, it's my current understanding)
I've also tried InvalidationListeners. Those seem to be processed before a change to the property is actually made, but I don't know how to make sure that the property's value doesn't change if the change-Alert is not confirmed.
How can I solve this problem?
Just check in the handlers for the controls if changeConfirmed is false; if it is show the confirm dialog. Then, still in the event handler, check again if changeConfirmed is true; if it is, change the value. If you want to revert the value in the control if the users denies confirmation, then write the code for that.
Here is a quick example based loosely on your example:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Optional;
public class HelloApplication extends Application {
private boolean changeConfirmed = false ;
#Override
public void start(Stage stage) throws IOException {
VBox root = new VBox(5);
HBox nameBox = new HBox(5);
HBox ageBox = new HBox(5);
Label nameLabel = new Label();
Label ageLabel = new Label();
Slider slider = new Slider();
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setMin(0);
slider.setMax(120);
TextField nameTF = new TextField();
slider.valueChangingProperty().addListener((obs, isFinishedChanging, isNowChanging) -> {
if (isFinishedChanging) {
if (!changeConfirmed) {
showConfirmDialog();
}
if (changeConfirmed) {
ageLabel.setText(String.valueOf((int)slider.getValue()));
} else {
// revert to current value:
String ageStr = ageLabel.getText();
int age = ageStr.isEmpty() ? 0 : Integer.parseInt(ageStr);
slider.setValue(age);
}
}
});
nameTF.setOnAction(e -> {
if (! changeConfirmed) {
showConfirmDialog();
}
if (changeConfirmed) {
nameLabel.setText(nameTF.getText());
} else {
nameTF.setText(nameLabel.getText());
}
});
nameBox.getChildren().addAll(new Label("Name:"), nameLabel);
ageBox.getChildren().addAll(new Label("Age:"), ageLabel);
Button clearConfirm = new Button("Request to confirm changes");
clearConfirm.setOnAction(e -> changeConfirmed = false);
root.getChildren().addAll(nameBox, ageBox, nameTF, slider, clearConfirm);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 400, 300);
stage.setScene(scene);
stage.show();
}
private void showConfirmDialog() {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirm Change");
alert.setHeaderText("A change occurred.");
alert.setContentText("Do you really want to change the value?");
Optional<ButtonType> buttonType = alert.showAndWait();
if(buttonType.isPresent() && buttonType.get().equals(ButtonType.OK)) {
changeConfirmed = true;
}
}
public static void main(String[] args) {
launch();
}
}
so I am trying to switch to a different scene in javafx. I am working on a project where the user will select on a food category via a combobox, which will switch to a new scene that has all the recipes under that specific category.
The problem is I am able to load my MainMenuScene, but I am not sure how to switch to a different scene, which I think is because of how I have structured my code.
My code is structured where I can GUIAPP (which starts the entire GUI)
private static View myView;
private static Recipe myRecipe;
public GUIApp() {
myView = new View();
myRecipe = new Recipe();
}
public static View getView() {
return myView;
}
public static Recipe getRecipe() {
return myRecipe;
}
#Override
public void start(Stage primaryStage) throws Exception {
System.out.println("Starting app...");
myView.setStage(primaryStage);
}
public static void main(String [] args) {
myRecipe = new Recipe();
launch(args);
}
}
Then View, which sets the primary Stage (which is MainMenuScene)
private Stage myStage;
private Scene myMainMenuScene;
private Scene myMealScene;
public View() {
myMainMenuScene = new MainMenuScene(new BorderPane());
}
public Stage getStage() {
return myStage;
}
public Scene getMealScene() {
return myMealScene;
}
public void setStage(Stage primaryStage) {
myStage = primaryStage;
myStage.setScene(myMainMenuScene);
myStage.setTitle("Recipe Database");
myStage.setWidth(600);
myStage.setHeight(400);
Scene scene = myMainMenuScene;
myStage.setScene(scene);
myStage.show();
}
}
Here is MainMenuScene, where it calls the recipe code I had previously made
private BorderPane myRoot;
private String f, t;
Label label = new Label();
public MainMenuScene(Parent root) {
super(root);
myRoot = (BorderPane) root;
BorderPane titleBox = new BorderPane();
titleBox.setStyle("-fx-font: 24 arial;");
myRoot.setTop(titleBox);
Text title = new Text("Recipe Database Tool");
title.setFont(new Font(50));
titleBox.setCenter(title);
//VBox and HBox creation
VBox leftBox = new VBox();
VBox rightBox = new VBox();
VBox centerBox = new VBox();
//Button search = new Button("Recipe Categories");
Button create = new Button("Create/Upload a New Recipe");
//Creates a combobox that gets the category name from Recipe
ComboBox<String> search = new ComboBox<String>();
search.getItems().addAll(GUIApp.getRecipe().getCategory());
search.setOnAction((e) -> {
search.getSelectionModel().selectFirst();
});
/*
****//Create a button that switches to MealScene when a category is selected
Button select = new Button("Select");
select.setOnAction((e) -> {
View.getStage().setScene(View.getMealScene());****
});
*/
//myRoot for each Box
myRoot.setLeft(leftBox);
myRoot.setRight(rightBox);
myRoot.setCenter(centerBox);
//adding the search categories button to the left box
leftBox.setAlignment(Pos.CENTER);
leftBox.setSpacing(30);
leftBox.getChildren().add(search);
//adding the create a new recipe to the right box
rightBox.setAlignment(Pos.CENTER);
rightBox.setSpacing(30);
rightBox.getChildren().add(create);
}
}
I tried calling the button by using View, but I am getting an error that I am not sure how to fix.
Here's the error: It's asking for View.getStage() to make getStage a static method in View, which I don't want to do and View.getMealScene to also become static
Please let me know! I would love to learn how to prevent this in the future
Hello having trouble creating an array from a dialog box. I am able to type in the dialog and print out index [0] of ArrayList. But when I press Ok it restarts and replaces index [0] instead of adding to the ArrayList . How do I get the application to keep running instead of restarting?
Original Assignment:
Going back to the GUI assignment. You can modify this to use JavaFX
if you want to.
Create an application that has a button that has “Enter your info.”
When clicked it will present a JDialog that has labels and text boxes
that allow the user to enter their name, email, and phone number. The
JDialog will have buttons OK and Cancel.
When the user clicks Cancel, the dialog will go away without doing
anything else.
When the user clicks OK, the user’s information will be extracted from
the dialog, and dumped out on the console. Notice that you only are
listening for Click events. We will add to that spec.
Define a class to hold the info for a single person. Declare an
ArrayList of this type. When the user clicks OK, extract the info
from the dialog. This time, pass the info to the constructor method
of your class that will hold the info. Add this newly created object
to your array list.
Using an enhanced for loop, dump the ArrayList onto the console.
Add several user info's to the ArrayList, each time, dumping the
entire list to the console.
Sort the ArrayList. Dump the ArrayList onto the console.
public class UsefulGUI extends Application {
#Override
public void start(Stage primaryStage) {
Button button = new Button();
button.setText("Enter your info");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
dialogBox();
}
});
StackPane pane = new StackPane();
pane.getChildren().add(button);
Scene scene = new Scene(pane, 500, 300);
primaryStage.setTitle("Useful GUI");
primaryStage.setScene(scene);
primaryStage.show();
}
public class User {
private String name;
private String email;
private String phone;
public User(String n, String e, String p) {
this.name = n;
this.email = e;
this.phone = p;
}
#Override
public String toString() {
return "Name: " + name + " Email: " + email + " Phone: " + phone;
}
}
public void dialogBox() {
Dialog<User> dialog = new Dialog<>();
ArrayList<User>list = new ArrayList<User>();
dialog.setTitle("User info");
Label name = new Label("Name: ");
Label email = new Label("Email: ");
Label phone = new Label("Phone: ");
TextField textName = new TextField();
TextField textEmail = new TextField();
TextField textPhone = new TextField();
GridPane grid = new GridPane();
grid.add(name, 1, 1);
grid.add(textName, 2, 1);
grid.add(email, 1, 2);
grid.add(textEmail, 2, 2);
grid.add(phone, 1, 3);
grid.add(textPhone, 2, 3);
dialog.getDialogPane().setContent(grid);
ButtonType buttonType = new ButtonType("Ok", ButtonData.OK_DONE);
dialog.getDialogPane().getButtonTypes().addAll(buttonType, ButtonType.CANCEL);
dialog.setResultConverter(new Callback<ButtonType, User>() {
#Override
public User call(ButtonType b) {
if (b == buttonType) {
return new User(textName.getText(), textEmail.getText(), textPhone.getText());
}
return null;
}
});
Optional<User>info = dialog.showAndWait();
// Adds user to list
list.add(new User(textName.getText(), textEmail.getText(), textPhone.getText()));
System.out.print("Info Added.\n NEWUSER ");
System.out.println(new User(textName.getText(), textEmail.getText(), textPhone.getText()));
//Collections.sort(list);
for (int i = 0; i < list.size(); i++) {
System.out.println(i + ". " + list.get(i));
}
//if (info.isPresent()) {
// System.out.println(info.get());
//}
}
public void quitApplication() {
Platform.exit();
}
public static void main(String[] args) {
launch(args);
}
}
I'm a really new programmer so idk if this question sounds really stupid but..
This is my main:
package culminating;
import javafx.application.Application;
& all other necessary imports...
public class CulminatingMAIN extends Application {
//Set Global variables
int count = 0;
String name;
String gender = "Boy";
Label testLabel = new Label(gender + " has been selected");
#Override
public void start(Stage primaryStage) throws Exception {
/**
* ************************ SCENE 1 WORK *************************
*/
TextField nameTextField = new TextField();
nameTextField.setMaxWidth(100);
Label nameLabel = new Label("Please enter your name.");
Label genderLabel = new Label();
Label titleLabel = new Label("Math Adventure!");
titleLabel.setFont(Font.font("Arial", FontWeight.BOLD, 30));
Rectangle titleRectangle = new Rectangle();
titleRectangle.setFill(Color.TOMATO);
titleRectangle.setWidth(280);
titleRectangle.setHeight(60);
titleRectangle.setStroke(Color.BLACK);
titleRectangle.setStrokeWidth(2.0);
StackPane root = new StackPane(titleRectangle, titleLabel);
//Set VBox properties
VBox vbox1 = new VBox(25);
vbox1.setAlignment(Pos.TOP_CENTER);
vbox1.setPadding(new Insets(60, 0, 0, 0));
vbox1.setStyle("-fx-background-color: lightskyblue");
HBox genderBtnBox = new HBox(25);
genderBtnBox.setAlignment(Pos.CENTER);
//Set Scene 1 buttons
Button enterNameBtn = new Button("Enter");
Button goToScene2Btn = new Button("Continue");
//Set Radio Button functionality here
final ToggleGroup genderGroup = new ToggleGroup();
RadioButton rb1 = new RadioButton("Boy");
rb1.setToggleGroup(genderGroup);
rb1.setUserData("Boy");
rb1.setSelected(true);
RadioButton rb2 = new RadioButton("Girl");
rb2.setToggleGroup(genderGroup);
rb2.setUserData("Girl");
//Add panes, labels and buttons to the VBox
vbox1.getChildren().addAll(root, nameLabel, nameTextField, enterNameBtn, genderLabel, genderBtnBox);
Scene scene = new Scene(vbox1, 500, 500);
primaryStage.setScene(scene);
primaryStage.setTitle("Culminating Project");
primaryStage.show();
/**
* ************************ SCENE 2 WORK *************************
*/
//THIS IS ROUGH WORK SO FAR
//Here, testing out new scene to see that it loads properly (and it does)
Circle testCircle = new Circle();
testCircle.setRadius(30);
testCircle.setFill(Color.YELLOW);
StackPane testPane = new StackPane(testCircle, testLabel);
Scene scene2 = new Scene(testPane, 500, 500);
/**
* ************************ EVENTS *************************
*/
//Stores user-entered name and prompts for user gender. Adds Continue button
enterNameBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if ((count < 1) && (!nameTextField.getText().isEmpty())) {
name = nameTextField.getText();
genderLabel.setText("Hi " + name + "! Please select whether you are a boy or girl.");
genderBtnBox.getChildren().addAll(rb1, rb2);
vbox1.getChildren().add(goToScene2Btn);
count++;
}
}
});
//When pressed, changes the scene so that scene 2 is set instead
goToScene2Btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
primaryStage.setScene(scene2);
}
});
//Radio button selection is stored in gender variable
genderGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
#Override
public void changed(ObservableValue<? extends Toggle> ov,
Toggle old_toggle, Toggle new_toggle) {
if (genderGroup.getSelectedToggle() != null) {
gender = genderGroup.getSelectedToggle().getUserData().toString();
testLabel.setText(gender + " has been selected");
}
}
});
if (gender.equals("boy")){
{
}
}
else if (gender.equals("girl")){
{
}
}
}
public static void main(String[] args) {
launch(args);
}
}
Now I have another class called CharacterGraphic, which I want to call and make the graphic I created in it appear.
package culminating;
& all the other imports
public class CharacterGraphic extends Culminating_JavaFX {
public void start(Stage primaryStage) throws Exception {
String gender = "boy";
Pane pane = new Pane();
pane.setStyle("-fx-background-color: LIGHTBLUE");
pane.setPrefSize(200, 200);
Circle head = new Circle();
head.setRadius(50);
head.setCenterX(240);
head.setCenterY(120);
head.setFill(Color.BURLYWOOD);
etc etc (all other graphics i made)
How do I do this???? And where would I do this?? Any answers really, really appreciated!
I have a grid pane which contains a number of buttons (normally something between 10 and 25) with five buttons per row (and however many are left in the last row). The number of buttons (and the buttons itself) might change during program execution. When that happens, the new buttons should be displayed. How can I achieve that? Here is a mini-example:
public class GridButtons extends Application {
List<String> buttonTexts = new ArrayList<>();
GridPane buttonGrid = new GridPane();
GridPane bgGrid = new GridPane();
#Override
public void start(Stage primaryStage) {
Button changeButtonsButton = new Button("Change BTNs");
changeButtonsButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
changeButtonTexts();
}
});
bgGrid.add(changeButtonsButton, 0, 0);
changeButtonTexts();
bgGrid.add(buttonGrid, 1, 0);
Scene scene = new Scene(bgGrid, 440, 140);
primaryStage.setScene(scene);
primaryStage.show();
}
public void updateButtonsGrid() {
buttonGrid = new GridPane();
for (int i = 0; i < buttonTexts.size(); i++) {
Button button = new Button(buttonTexts.get(i));
button.setMinWidth(70);
button.setMaxWidth(70);
buttonGrid.add(button, i % 5, i / 5);
System.out.println(buttonTexts.get(i));
}
// now the new GridPane should be displayed -> how?
}
public void changeButtonTexts() {
buttonTexts.clear();
Random random = new Random();
int buttonCount = random.nextInt(15) + 10;
for (int i = 0; i < buttonCount; i++) {
buttonTexts.add("Button " + i);
}
updateButtonsGrid();
}
public static void main(String[] args) {
launch(args);
}
}
Or are there better options than using a GridPane? Using a ListView<Button> and an ObservableList<Button> would work, but then the buttons are not displayed in a tabular form with five buttons in each row.
Creating a new GridPane is probably not what you want here. In the function updateButtonsGrid, change the line
buttonGrid = new GridPane();
to
buttonGrid.getChildren().clear();
If, for some reason, you are absolutely sure you need a new instance of GridPane, remove the old one from bgGrid, and add the new one. In your current code example the new instance of GridPane is never added to the scene graph.