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);
}
}
Related
I am currently trying to write a simple application in Java using JavaFX.
In the application I want to have a pop up window that prompts the user for input. This works fine, as long as the user doesn't try to open the pop up window again.
If he does that the following error occurs:
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Grid hgap=5.0, vgap=0.0, alignment=TOP_LEFTis already set as root of another scene
And here is the code that opens the window:
In the main view controller:
btAddChat.setOnAction(e -> lvItems.add(PopUpVC.display()));
And in the view controller for the pop up:
public class PopUpVC
{
private static final GridPane root = new GridPane();
private static final TextField tfInput = new TextField();
private static final Button btOK = new Button("OK");
private static String result;
private static Stage primaryStage = new Stage();
public static String display()
{
Scene scene = new Scene(root, 200, 50);
MainVC mvc = new MainVC();
root.setPadding(new Insets(10));
root.setHgap(5);
tfInput.setPrefWidth(scene.getWidth()*0.65);
root.add(btOK, 0, 0, 1, 1);
root.add(tfInput, 1, 0, 1, 1);
btOK.setOnAction(e ->
{
if(!tfInput.getText().equals(""))
{
primaryStage.close();
}
});
primaryStage.setResizable(false);
primaryStage.setScene(scene);
primaryStage.showAndWait();
return tfInput.getText();
}
I only copied the most important part, the actual error is a lot longer. I know what is causing the error (trying to open a window with the same root throws an error because the root is already in use), I just can't figure out how to resolve it.
Here is a picture of the application:
The top left button opens the pop up.
The pop up:
If there are any suggestions on how to resolve this issue I would be very glad to hear them, if there should be any another way to open a pop up window that prompts the user for text input, I would also be glad to hear about those!
Thanks a lot in advance!
The OP's solution:
I figured it out, easy thing really, I added a parameter to the start function so when I call it I just give it a new GridPane() and it works perfectly fine.
Is really the wrong approach. As #James_D pointed out, static is not a good idea for anything like this. Trying to keep with the original design as much as possible, I'd suggest this, which builds the PopUp just once, and re-displays it:
public class PopUp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button button = new Button("Click Me");
PopUpVC popUpVC = new PopUpVC();
button.setOnAction(evt -> {
popUpVC.display();
});
primaryStage.setScene(new Scene(button));
primaryStage.show();
}
public class PopUpVC {
private final TextField tfInput = new TextField();
private Stage primaryStage = new Stage();
public PopUpVC() {
GridPane root = new GridPane();
Scene scene = new Scene(root, 200, 50);
root.setPadding(new Insets(10));
root.setHgap(5);
tfInput.prefWidthProperty().bind(scene.widthProperty().multiply(0.65));
Button btOK = new Button("OK");
root.add(btOK, 0, 0, 1, 1);
root.add(tfInput, 1, 0, 1, 1);
btOK.setOnAction(e -> {
if (!tfInput.getText().equals("")) {
primaryStage.close();
}
});
primaryStage.setResizable(false);
primaryStage.setScene(scene);
}
public String display() {
primaryStage.showAndWait();
return tfInput.getText();
}
}
}
When you have something that's completely static, like PopUpVC, that's a hint that it's just code that you've moved out of somewhere else. This is useful, and a good practice, if you are calling the methods from a variety of other classes, when it saves code duplication. However, you shouldn't have JavaFX elements as static fields in such a class.
In this case, you can do away with PopUpVC and move all of the code into a local method:
public class PopUp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button button = new Button("Click Me");
button.setOnAction(evt -> {
displayPopUpVC();
});
primaryStage.setScene(new Scene(button));
primaryStage.show();
}
public String displayPopUpVC() {
TextField tfInput = new TextField();
Stage primaryStage = new Stage();
GridPane root = new GridPane();
Scene scene = new Scene(root, 200, 50);
root.setPadding(new Insets(10));
root.setHgap(5);
tfInput.prefWidthProperty().bind(scene.widthProperty().multiply(0.65));
Button btOK = new Button("OK");
root.add(btOK, 0, 0, 1, 1);
root.add(tfInput, 1, 0, 1, 1);
btOK.setOnAction(e -> {
if (!tfInput.getText().equals("")) {
primaryStage.close();
}
});
primaryStage.setResizable(false);
primaryStage.setScene(scene);
primaryStage.showAndWait();
return tfInput.getText();
}
}
This behaves slightly different from the first solution because it doesn't retain the text in the TextField between calls. But the default text could be passed in a parameter if you wanted.
But, also as #James_D has pointed out, TextInputDialog does exactly what you want. Plus it does it with about 4 lines of code:
public class PopUp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button button = new Button("Click Me");
TextInputDialog dialog = new TextInputDialog();
dialog.setHeaderText(null);
dialog.setTitle("Chat");
dialog.setGraphic(null);
button.setOnAction(evt -> {
dialog.showAndWait();
});
primaryStage.setScene(new Scene(button));
primaryStage.show();
}
}
how can I refactor the following code so that only the code in deleteButton.setOnAction(deleteEvent -> {//only this code varies} changes. Everything else will stay the same but the block of code in the lambda expression varies from time to time when I call the class from another class. The block of code that goes through the lambda expression is supposed to be a void method.
public class A {
public void test() {
// ensure that user can't close the alert
Stage primaryStage = (Stage) RootLayoutController.getRootLayout().getScene().getWindow();
JFXAlert<javafx.scene.control.ButtonType> alert = new JFXAlert<>(primaryStage);
alert.initModality(Modality.APPLICATION_MODAL);
alert.setOverlayClose(false);
//create font awesome icon
String ICON = "\uf071";
Label labelIcon = new Label(ICON);
labelIcon.setStyle("-fx-font-family: 'FontAwesome'; -fx-font-size: 60px; -fx-text-fill: #D34336;");
labelIcon.setPadding(new Insets(0,5,0,0));
// Create the content of the JFXAlert with JFXDialogLayout
JFXDialogLayout layout = new JFXDialogLayout();
Label labelHeading = new Label("Alert Notification");
Label labelBody = new Label("Are you sure you want to delete this?");
layout.setHeading(labelHeading);
layout.setBody(new VBox(new HBox(labelIcon, labelBody)));
// Buttons get added into the actions section of the layout.
JFXButton deleteButton = new JFXButton("Delete");
deleteButton.setDefaultButton(true);
deleteButton.setOnAction(deleteEvent -> {
//only this block of code changes
alert.hideWithAnimation();
});
JFXButton cancelButton = new JFXButton("Cancel");
cancelButton.setCancelButton(true);
cancelButton.setOnAction(closeEvent -> alert.hideWithAnimation());
layout.setActions(deleteButton, cancelButton);
alert.setContent(layout);
alert.showAndWait();
}
}
It is not entirely clear from your question what you are trying to accomplish, but I will take a wild stab at it.
If you are looking to be able to pass a code block to the deleteButton.setOnAction() method, you could use an Interface and pass implementations of that interface to the A class. Then just pass that reference to an internal method for the onAction lambda.
Here is a very quick example of how you could do something like this:
Main.java:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Action button
Button btnDoSomething = new Button("Do something...");
btnDoSomething.setOnAction(e -> doTheThings(new ImplDoSomething()));
Button btnDoSomethingElse = new Button("Do something else...");
btnDoSomethingElse.setOnAction(e -> doTheThings(new ImplDoSomethingElse()));
VBox mainPane = new VBox(5);
mainPane.setAlignment(Pos.CENTER);
mainPane.setPadding(new Insets(10));
mainPane.getChildren().addAll(btnDoSomething, btnDoSomethingElse);
primaryStage.setScene(new Scene(mainPane));
primaryStage.show();
}
private void doTheThings(IParameterMethod parameterMethod) {
parameterMethod.call();
}
}
The IParameterMethod.java Interface:
public interface IParameterMethod {
void call();
}
Then you can create as many classes as you like that implement that interface, each with their own call() method, allowing you to execute different code.
ImplDoSomething.java
public class ImplDoSomething implements IParameterMethod {
#Override
public void call() {
System.out.println("Doing something!");
}
}
ImplDoSomethingElse.java:
public class ImplDoSomethingElse implements IParameterMethod {
#Override
public void call() {
System.out.println("Doing something else!");
}
}
This should be easily adapted for your project.
I am crazy about the feature of JavaFX, in Swing, I could do,
#Override
public void onPluginRegistered(final GamePlugin plugin) {
JRadioButtonMenuItem gameMenuItem = new JRadioButtonMenuItem(plugin.getGameName());
gameMenuItem.setSelected(false);
gameMenuItem.addActionListener(event -> {
if (core.getPlayers().isEmpty()) {
// Can't start a game with no players.
showErrorDialog(frame, ERROR_NO_PLAYERS_TITLE, ERROR_NO_PLAYERS_MSG);
gameGroup.clearSelection();
} else {
core.startNewGame(plugin);
}
});
gameGroup.add(gameMenuItem);
newGameMenu.add(gameMenuItem);
}
if I want to add a radio item whenever a plugin has registered.
However in JavaFX, it seems, you can't declare any global item of JavaFX, because once the start() is called, it starts a new constructor and everything you've done before is nothing (there is no variable share to me).
Here is my Javafx code.
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 500, 500);
scene.getStylesheets().add("./Buttons.css");
Region spacer = new Region();
spacer.setMinWidth(10);
primaryStage.setScene(scene);
primaryStage.show();
TabPane tabPane = new TabPane();
Tab tabData = new Tab("Get your data");
tabPane.getTabs().add(tabData);
Tab tabDisplay = new Tab("Visualize your data");
tabPane.getTabs().add(tabDisplay);
pluginGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>(){
#Override
public void changed(ObservableValue<? extends Toggle> ov,
Toggle old_toggle, Toggle new_toggle) {
if (pluginGroup.getSelectedToggle() != null) {
RadioButton chk = (RadioButton) new_toggle.getToggleGroup().getSelectedToggle();
chk.getText();
}
}
});
root.setCenter(tabPane);
FlowPane inputPanel = new FlowPane();
TextField source = new TextField ();
Button confirmButton = new Button("Get Your Resource!");
confirmButton.getStyleClass().add("GREEN");
inputPanel.getChildren().addAll(new Label("Input your source:"),
spacer, source, confirmButton);
root.setBottom(inputPanel);
RadioButton defaultBtn = new RadioButton("No data plugin are registered");
FlowPane pane = new FlowPane();
pane.getChildren().addAll(new Label("Select your data source"), spacer);
if (radioButtonBox != null) {
pane.getChildren().add(radioButtonBox);
}
tabData.setContent(pane);
}
#Override
public void onPluginRegistered(DataPlugin plugin) {
RadioButton button = new RadioButton(plugin.getName());
button.setToggleGroup(pluginGroup);
radioButtonBox.getChildren().add(button);
}
public void caller(String[] args) {
launch(args);
}
I want to initialize the javafx program from,
public static void main(String[] args) throws Exception {
DataFramework core = new ConcreteDataFramework();
GuiFramework gui = new GuiFramework(core);
core.addGuiListener(gui);
gui.caller(args);
core.registerPlugin(new CsvData());
}
It is weird that I can't add any radio button to the existing radioButtonBox every time I call onPluginRegistered(DataPlugin plugin) (The new radiobutton does not show up)
You should consider the start() method as the replacement for the main method. If your application needs access to some kind of service or model, create it in the start() (or init()) method. I would actually recommend making the Application subclass (which is inherently not reusable) as minimal as possible - it should just do the startup work - and factoring the remaining GUI code into a separate class. (If you use FXML, the FXML file can define the UI, and the Application subclass is then already pretty minimal: it just loads and displays the FXML.)
You haven't really provided enough context to make it clear what's going on here, but I'm guessing GuiFramework is the Application subclass you've shown part of, and DataFramework is an interface of some kind. I also assume GuiFramework is implementing some interface that defines the onPluginRegistered method.
So I would do:
public class GuiFramework implements PluginAware {
private final BorderPane root ;
private final DataFramework dataFramework ;
public GuiFramework(DataFramework dataFramework) {
this.dataframework = dataFramework ;
this.root = new BorderPane();
TabPane tabPane = new TabPane();
Tab tabData = new Tab("Get your data");
tabPane.getTabs().add(tabData);
// etc etc (remaining code from your start() method)
}
public Parent getView() {
return root ;
}
#Override
public void onPluginRegistered(DataPlugin plugin) {
RadioButton button = new RadioButton(plugin.getName());
button.setToggleGroup(pluginGroup);
radioButtonBox.getChildren().add(button);
}
}
and define a Main class for starting the application:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
DataFramework core = new ConcreteDataFramework();
GuiFramework gui = new GuiFramework(core);
core.addGuiListener(gui);
Scene scene = new Scene(gui.getView(), 500, 500);
scene.getStylesheets().add("./Buttons.css");
primaryStage.setScene(scene);
primaryStage.show();
core.registerPlugin(new CsvData());
}
// for environments not supporting JavaFX launch automatically:
public static void main(String[] args) {
launch(args);
}
}
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()
*/
}
If I have a class that extends superclass that has a .setContent(Pane pane) method, am I able to change the pane from within the class.
For example: When the example button is pushed, I would like to set the content to stackPane2. (this.setContent(stackPane2);).
public class AClass extends SomeClass{
public AClass(){
super();
HBox hBox = new HBox();
Button exampleButton = new Button("Example");
exampleButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
//Change the content here
}
});
StackPane stackPane1 = new StackPane();
stackPane1.getChildren().addAll(hBox);
StackPane stackPane2 = new StackPane();
stackPane2.getChildren().add(/*Some other stuff*/);
this.setContent(stackPane1);
}
}
Can this be done? If so, how? Otherwise what could be a possible workaround.
I'm not sure if i missing something, but i think that the easiest way if you don't have some much code is declare stackPane1 and stackPane2 as final fields and then call setContent from the button listener.
public class AClass extends SomeClass{
private final StackPane stackPane1;
private final StackPane stackPane2;
public AClass(){
super();
HBox hBox = new HBox();
Button exampleButton = new Button("Example");
exampleButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
if (somenthingHapper()) {
this.setContent(stackPane1);
} else {
this.setContent(stackPane2);
}
}
});
stackPane1 = new StackPane();
stackPane1.getChildren().addAll(hBox);
stackPane2 = new StackPane();
stackPane2.getChildren().add(/*Some other stuff*/);
this.setContent(stackPane1);
}
}