I am using JavaFX Netbeans and Scene Builder for my program. I am trying to create a student information input scene. I have all of the inputs working and going to a text file right now. It also displays a Success pop up box. However, I am trying to make it so that if one of the inputs is blank, nothing will be inputted and an error popup will come up. Right now both popups work, but it is broken and only the success comes up. No matter if all inputs are there or not, the error box will come up 4 times. I cannot figure out why because I have each if statement there. I also don't know where to start with not inputting any information if one field is not filled out.
import javafx.collections.*;
import javafx.event.ActionEvent;
import javafx.fxml.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.io.*;
import java.net.URL;
import java.nio.file.*;
import java.nio.file.StandardOpenOption;
import java.util.ResourceBundle;
public class CController implements Initializable {
#FXML
private Button button;
#FXML
private Text Student;
#FXML
private Button Add;
#FXML
private ComboBox Grade;
#FXML
private ComboBox Type;
#FXML
private TextField Name;
#FXML
private TextField ID;
ObservableList<String> GRADES = FXCollections.observableArrayList("9", "10", "11", "12");
ObservableList<String> EVENTS = FXCollections.observableArrayList("Business Law and Ethics", "Buying and Merchandising", "Financial Services", "Hospitality Services", "Marketing Communications", "Sports and Entertainment Marketing", "Travel and Tourism", "Accounting Applications", "Apparel and Accessories Marketing", "Automotive Services Marketing", "Business Finance", "Business Services Marketing", "Food Marketing", "Hotel and Lodging Management", "Human Resources Management", "Marketing Management", "Quick Serve Restaurant Management", "Restaurant and Food Service Management", "Retail Merchandising", "Sports and Entertainment Marketing");
#FXML
private void handleButtonAction(ActionEvent event) throws IOException {
Parent FXMLDocument2Parent = FXMLLoader.load(getClass().getResource("B.fxml"));
Scene FXMLDocument2Scene = new Scene(FXMLDocument2Parent);
Stage AppStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
AppStage.setScene(FXMLDocument2Scene);
AppStage.show();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
Grade.setItems(GRADES);
Type.setItems(EVENTS);
}
#FXML
public void addtolist(ActionEvent e) throws IOException {
Alert success = new Alert(Alert.AlertType.INFORMATION);
success.setTitle("Information");
success.setHeaderText(null);
success.setContentText("Student Added");
success.showAndWait();
Alert nosave = new Alert(Alert.AlertType.INFORMATION);
String idinput = ID.getText();
SendToText("\r\n");
SendToText(idinput);
if (idinput.isEmpty())
nosave.setTitle("Error");
nosave.setHeaderText(null);
nosave.setContentText("Please Enter All Student Information");
nosave.showAndWait();
String nameinput = Name.getText();
SendToText(",");
SendToText(nameinput);
if (nameinput.isEmpty())
nosave.setTitle("Error");
nosave.setHeaderText(null);
nosave.setContentText("Please Enter All Student Information");
nosave.showAndWait();
String grade;
grade = (String) Grade.getValue();
SendToText(",");
SendToText(grade);
if (grade.isEmpty())
nosave.setTitle("Error");
nosave.setHeaderText(null);
nosave.setContentText("Please Enter All Student Information");
nosave.showAndWait();
String event;
event = (String) Type.getValue();
SendToText(",");
SendToText(event);
if (event.isEmpty())
nosave.setTitle("Error");
nosave.setHeaderText(null);
nosave.setContentText("Please Enter All Student Information");
nosave.showAndWait();
}
private void SendToText(String cartone) throws IOException {
Path file = Paths.get("C:/Users/Shaheer.K/Documents/Shaheer/IAiffy/src/ia/Extra/list.txt");
byte[] data = cartone.getBytes();
OutputStream output = null;
try {
output = new
BufferedOutputStream(Files.newOutputStream(file, StandardOpenOption.APPEND));
output.write(data);
output.flush();
output.close();
} catch (IOException e) {
System.out.println("Message: " + e);
}
}
}
Related
I'm currently working on a password manager. Before making any changes to a certain service, the program will ask the user for a password for authorization and then proceed to show the appropriate dialog, if the password is correct.
The issue that I'm having is that if I go through the cycle of putting in my password to make the change, click "ok", and then proceeding to make changes on the shown dialog, on the next turn if instead of putting the password when prompted I close the prompt, then the program retrieves the password from the previous iteration although it has been explicitly cleared. Resulting in the concurrent dialog showing, which is only supposed to show if you put in the correct password.
private void handleEditButton(MouseEvent event) {
Optional<String> rslt = passwordConfirmDialog.showAndWait();
if (rslt.get().equals(""))
return; //Do not proceed
String userInput = rslt.get().trim();
// Complex expression, but use of && statement is necessary to avoid an
// unecessary call to db and have return statement on this IF
if (!(!userInput.isBlank() && isCorrectPassword(userInput))) {
// show dialog
AlertConfigs.invalidPasswordTransactionFailed.showAndWait();
return;
}
System.out.println("Edit Handler: Correct password. -> " + userInput);
//Proceed to show next dialog...
private void initializePasswordConfirmDialog() {
passwordConfirmDialog.setTitle("User Account Control");
passwordConfirmDialog.setHeaderText("Please enter your password to continue.");
// Set the button types.
ButtonType ok = new ButtonType("Ok", ButtonData.OK_DONE);
passwordConfirmDialog.getDialogPane().getButtonTypes().addAll(ok, ButtonType.CANCEL);
final PasswordField psField = new PasswordField();
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(20, 150, 10, 10));
grid.add(new Label("Please Enter your password"), 0, 0);
grid.add(psField, 1, 0);
passwordConfirmDialog.getDialogPane().setContent(grid);
passwordConfirmDialog.setResultConverter(buttonType -> {
String rslt = "";
if (buttonType == ok) {
rslt = psField.getText();
}
psField.clear();
return rslt;
});
}
I've posted a video on YouTube to help visualize the problem. https://youtu.be/sgayh7Q7Ne8
The PasswordField in initializePasswordConfirmDialog() is cleared because whenever I run the the prompt the second time, the PasswordField is blank (visually). Nevertheless, for some reason it still grabs the result from the previous iteration.
The initializePasswordConfirmDialog() is called once inside the constructor and is responsible for set the passwordConfirmDialog variable with the adequate properties.
Some additional code:
HomeController.java
#FXML
private GridPane servicesGrid;
private Dialog<String> passwordConfirmDialog;
private Dialog<Service> editServiceDialog;
private final int NUM_COLUMNS = 7;
public HomeController() {
passwordConfirmDialog = new Dialog<>();
initializePasswordConfirmDialog();
editServiceDialog = new Dialog<>();
}
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
loadServicesGridpane();
}
private void loadServicesGridpane() {
ArrayList<Service> currS = acct.getServices();
// int currentRow = 1;
for (Service s : currS)
addRowToServiceGrid(s);
}
private void addRowToServiceGrid(Service s) {
int rowIdx = servicesGrid.getChildren().size() / 4;
Button editButton = new Button("Edit");
editButton.setOnMouseClicked(event -> {
handleEditButton(event);
});
Button deleteButton = new Button("Delete");
deleteButton.setOnMouseClicked(event -> {
handleDeleteButton(event);
});
deleteButton.setId(s.getServiceName());
Label currServiceName = new Label(s.getServiceName());
currServiceName.setId(s.getServiceName());
Label currUsername = new Label(s.getServiceUsername());
Label currPassword = new Label(s.getServicePassword());
Label dateCreated = new Label(s.getDateCreated());
Label lastPssdChange = new Label(s.getLastPasswordChange());
servicesGrid.addRow(rowIdx, currServiceName, currUsername, currPassword, dateCreated, lastPssdChange,
deleteButton, editButton);
}
To study the problem in isolation, I refactored this example to permit reusing the dialog. As shown below, reusing the dialog requires clearing the password field. Replace the parameter dialog with an invocation of createDialog() to see that creating the dialog each time does not require clearing the password field. Comparing the profile of each approach may help you decide which approach is acceptable; in my experiments, reuse added negligible memory overhead (~250 KB), and it protracted garbage collection slightly(~50 ms).
#!/bin/sh
java … DialogTest -reuse &
pid1=$!
java … DialogTest -no-reuse &
pid2=$!
echo $pid1 $pid2
jconsole $pid1 $pid2
Unfortunately, creating the dialog each time may only appear to solve the problem; it may have exposed a latent synchronization problem. In particular, verify that your result converter's callback executes on the JavaFX Application Thread. To illustrate, I've added a call to Platform.isFxApplicationThread() in resultsNotPresent() below.
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* #see https://stackoverflow.com/q/73328282/230513
* #see https://stackoverflow.com/a/44172143/230513
*/
public class DialogTest extends Application {
private static boolean REUSE_DIALOG = true;
private record Results(String text, String pass) {
private static Results of(String text, String pass) {
return new Results(text, pass);
}
}
#Override
public void start(Stage stage) {
var label = new Label("Reuse: " + REUSE_DIALOG);
var button = new Button("Button");
if (REUSE_DIALOG) {
var dialog = createDialog();
button.setOnAction(e -> showDialog(dialog));
} else {
button.setOnAction(e -> showDialog(createDialog()));
}
stage.setScene(new Scene(new HBox(8, label, button)));
stage.show();
}
private Dialog<Results> createDialog() {
var dialog = new Dialog<Results>();
dialog.setTitle("Dialog Test");
dialog.setHeaderText("Please authenticate…");
var dialogPane = dialog.getDialogPane();
dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
var text = new TextField("Name");
var pass = new PasswordField();
dialogPane.setContent(new VBox(8, text, pass));
dialog.showingProperty().addListener((o, wasShowing, isShowing) -> {
if (isShowing) {
Platform.runLater(pass::requestFocus);
}
});
dialog.setResultConverter((ButtonType bt) -> {
if (ButtonType.OK == bt) {
var results = Results.of(text.getText(), pass.getText());
pass.clear();
return results;
}
pass.clear();
return null;
});
return dialog;
}
private void showDialog(Dialog<Results> dialog) {
var optionalResult = dialog.showAndWait();
optionalResult.ifPresentOrElse(
(var results) -> System.out.println(results),
(this::resultsNotPresent));
}
private void resultsNotPresent() {
System.out.println("Canceled on FX application thread: "
+ Platform.isFxApplicationThread());
}
public static void main(String[] args) {
if (args.length > 0) {
REUSE_DIALOG = args[0].startsWith("-r");
}
launch(args);
}
}
I am in the process of learning Java and I can't seem to make this function work. I am working on a project for an inventory system. Where parts are added to an observable list. In the add part screen, I have two radio buttons to select whether the part is an InHouse made or OutSourced. I have an if statement using a toggle group to check which radio button is selected. I was trying to use an else statement to pass the values if it was an outsourced part. Right now it will pass the values correctly if the radio button is set to InHouse, but when set to Outsource it throws a null pointer exception at the line the if statement is on.
Here is the code I am trying to make work.
package ViewController;
import Model.InHouse;
import Model.Inventory;
import Model.OutSource;
import Model.Part;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.Optional;
import java.util.ResourceBundle;
public class AddPart implements Initializable {
public RadioButton addPartInHouse;
public TextField partIDTxtbox;
public TextField partNameTxtbox;
public TextField invTxtbox;
public TextField pricePerUnitTxtbox;
public TextField maxQtyTxtbox;
public TextField minQtyTxtbox;
public Button addPartSaveButton;
public Button addPartCancelButton;
public RadioButton addPartOutSource;
public Label companyNameLabel;
public TextField companyNamePrompt;
public ToggleGroup switchfield;
public void addPartInHouse(ActionEvent actionEvent) {
companyNameLabel.setText("Machine ID");
companyNamePrompt.setPromptText("Machine ID");
addPartOutSource.setSelected(false);
}
public void addPartOutsource(ActionEvent actionEvent) {
companyNameLabel.setText("Company Name");
companyNamePrompt.setPromptText("Company Name");
addPartInHouse.setSelected(false);
}
public void addPartSaveButton(ActionEvent e) throws IOException {
/*this is my line 55 below*/
if (this.switchfield.getSelectedToggle().equals(this.addPartInHouse)) {
Part partadd = new InHouse(0, "", 0.0, 0,0,0,0);
if(partIDTxtbox.getText().isEmpty()){
partadd.setPartID(Inventory.getPartIDCount());
}
if (!partNameTxtbox.getText().isEmpty()){
partadd.setPartName(partNameTxtbox.getText());
}
if (!pricePerUnitTxtbox.getText().isEmpty()){
partadd.setPartPrice(Double.parseDouble(pricePerUnitTxtbox.getText()));
}
if (!invTxtbox.getText().isEmpty()){
partadd.setPartInStock(Integer.parseInt(invTxtbox.getText()));
}
if(!minQtyTxtbox.getText().isEmpty()){
partadd.setMin(Integer.parseInt(minQtyTxtbox.getText()));
}
if(!maxQtyTxtbox.getText().isEmpty()){
partadd.setMax(Integer.parseInt(maxQtyTxtbox.getText()));
}
if(!companyNamePrompt.getText().isEmpty()){
((InHouse)partadd).setMachineID(Integer.parseInt(companyNamePrompt.getText()));
}
Inventory.addPart(partadd);
}
else{
Part partaddout = new OutSource(0, "", 0.0, 0,0,0,"");
if(partIDTxtbox.getText().isEmpty()){
partaddout.setPartID(Inventory.getPartIDCount());
}
if (!partNameTxtbox.getText().isEmpty()){
partaddout.setPartName(partNameTxtbox.getText());
}
if (!pricePerUnitTxtbox.getText().isEmpty()){
partaddout.setPartPrice(Double.parseDouble(pricePerUnitTxtbox.getText()));
}
if (!invTxtbox.getText().isEmpty()){
partaddout.setPartInStock(Integer.parseInt(invTxtbox.getText()));
}
if(!minQtyTxtbox.getText().isEmpty()){
partaddout.setMin(Integer.parseInt(minQtyTxtbox.getText()));
}
if(!maxQtyTxtbox.getText().isEmpty()){
partaddout.setMax(Integer.parseInt(maxQtyTxtbox.getText()));
}
if(!companyNamePrompt.getText().isEmpty()){
((OutSource)partaddout).setCompanyName((companyNamePrompt.getText()));
}
Inventory.addPart(partaddout);
}
Parent addPartSave = FXMLLoader.load(getClass().getResource("MainScreen.fxml"));
Scene scene = new Scene(addPartSave);
Stage window = (Stage) ((Node) e.getSource()).getScene().getWindow();
window.setScene(scene);
window.show();
}
public void addPartCancelButton(MouseEvent mouseEvent) throws IOException {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Cancel add part");
alert.setHeaderText("You are about to return to the Main screen!");
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK) {
Parent addPartCancel = FXMLLoader.load(getClass().getResource("MainScreen.fxml"));
Scene scene = new Scene(addPartCancel);
Stage window = (Stage) ((Node) mouseEvent.getSource()).getScene().getWindow();
window.setScene(scene);
window.show();
}
else{
return;
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
switchfield = new ToggleGroup();
this.addPartInHouse.setToggleGroup(switchfield);
}
}
'''
This is not an answer but it is more readable as an answer than as a comment.
Either switchfield is null or switchfield.getSelectedToggle() returns null.
Add the following line of code before line 55.
System.out.println(switchfield)
Then run your code. If it shows that switchfield is not null, then change it to
System.out.println(switchfield.getSelectedToggle())
And run the code again.
That should show that switchfield.getSelectedToggle() returns null.
Then you need to look at the code for method getSelectedToggle() in class ToggleGroup and see when that method returns null.
My guess is that method addPartSaveButton() is being called before you have selected one of the radio buttons.
Please help me solve the problem. There are two fxml files and their controllers:
sample.fxml, its controller ControllerMain (main window of the program)
find_win.fxml, its ControllerFind controller (modal window "text search")
In the modal window find_win.fxml there is a TextField into which the search text is entered, and the Find button, when clicked, ControllerFind must process the click and call the search method and highlight the search text in the TextArea element of the sample.fxml window.
<fx: include source = "sample.fxml" fx: id = "textAreaOne" />
and the inheritance of the ControllerMain by the ControllerFind controller does not help to achieve a solution - in the first case the entire window markup is included in the modal window completely, in the second case, the java.lang.reflect.InvocationTargetException is returned during an operation on the TextArea.
How to implement actions on elements of one window from another window?
I've found a solution elsewhere. Thanks to Comrade Antizam, who tried to help, but did not quite understand what I needed.
The solution described here is .
In short, it is necessary to create an instance of a controller-parent and a method that takes an instance of a controller-parent as a parameter in the controller-child. When a new window is opened from a controller-parent, get an instance of the controller-child and indicate to it through the created method "this".
Further, in the controller-child, it will be possible to access the elements of the parent controller.
controller-parent:
package sample;
public class ControllerMain {
private ControllerFind children; // controller-child
//main-window
#FXML
public TextArea textAreaOne;
#FXML
public MenuItem findMenuItem;
public void findAction(ActionEvent actionEvent) {
try {
Stage stageFind = new Stage();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXML/find_win.fxml"));
Parent root = loader.load();
stageFind.setTitle("Find");
stageFind.setMinHeight(200);
stageFind.setMinWidth(150);
stageFind.setResizable(false);
stageFind.setScene(new Scene(root));
stageFind.getIcons().add(new Image("image/search.png"));
stageFind.initModality(Modality.NONE);
stageFind.show();
children = loader.getController(); //getting controller of window find_win.fxml
children.setParent(this); //setting parent of the controller-child - this
} catch (IOException e) {
e.printStackTrace();
}
}
}
controller-child:
package sample.Controllers;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import sample.Classes.DialogManager;
import sample.ControllerMain;
public class ControllerFind {
//Window "Find"
#FXML public TextField searchTextField;
#FXML public Label findTextLabel;
#FXML public Button okTextFindButton;
#FXML public Button cancelTextFindButton;
private String text;
private ControllerMain controller;
public void setParent (ControllerMain controller){
this.controller = controller;
}
public ControllerFind getThis(){
return this;
}
public void initialize(){
System.out.println("psvm");
}
public void textFindOkButtonAction(ActionEvent actionEvent) {
text = (searchTextField.getText());
if (text.equals("")) {
DialogManager.showInfoDialog("Error!", "Enter text what you are looking for!");
} else {
if (controller.textAreaOne.getText() != null && !controller.textAreaOne.getText().isEmpty()) {
int index = controller.textAreaOne.getText().indexOf(text);
if (index == -1) {
DialogManager.showInfoDialog("Result", "There isn't text what you are looking for");
} else {
controller.textAreaOne.selectRange(index, index + text.length());
}
} else {
DialogManager.showInfoDialog("Error", "TextArea is empty!");
}
}
}
public void textFindCancelButtonAction(ActionEvent actionEvent) {
Node source = (Node) actionEvent.getSource();
Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
}
Vis-a-vis windows communication in this situation, it's optimal to use TextInputDialog something like this:
#Override
public void start(Stage primaryStage){
Button btn=new Button("Click");
VBox vbox=new VBox();
vbox.setAlignment(Pos.CENTER);
vbox.getChildren().addAll(btn);
Scene scene=new Scene(vbox, 200,200);
btn.setOnAction(e->
{
TextInputDialog dialog=new TextInputDialog();
Optional<String> result = dialog.showAndWait();
if (result.isPresent()){
System.out.println(result.get());
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
but text highlighting is not something that can be done easy.
You could do String search of TextArea text, compare it to result from another window then highlight it via
textArea.getSelectedRange(firstIndex, lastIndex);
firstIndex and lastIndex being indexes of textArea text for the word we are searching. Then having button on every click displaying next word occurancy inside text and highlighting it. But if you insist on highlighting every instance of word at the same time I would suggest using RichTextFX.
My problem is as follows,
For the sake of this question I reproduced the problem in a new project.
Say I have this application with a combobox in it, there could be 1 or more items in there. And I would like it to be so that when the user clicks an item in the combobox that 'something' happens.
I produced the following code:
obsvList.add("item1");
cbTest.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Item clicked");
}
});
This works when the application starts and an item is selected for the first time. This also works when there are 2 or more items in the combobox (when the user clicks item 1, then item 2, then item 1 for example)
However my problem is that when there is only 1 item in the combobox, let's say "item1". And the user reopens the combobox and clicks "item1" again then it won't redo the action.
It will only print the line "Item Clicked" when a 'new' item is clicked.
I hope it made it clear what the problem i'm experiencing is, if not please ask for clarification and I will give so where needed.
Thanks in advance!
The functionality of a combo box is to present the user with a list of options from which to choose. When you are using a control which implies selection, you should really ensure that the UI is always consistent with the option that is selected. If you do this, then it makes no sense to "repeat an action" when the user "reselects" the same option (because the UI is already in the required state). One approach to this is to use binding or listeners on the combo box's value:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class ComboBoxExample extends Application {
#Override
public void start(Stage primaryStage) {
ComboBox<Item> choices = new ComboBox<>();
for (int i = 1 ; i <=3 ; i++) {
choices.getItems().add(new Item("Choice "+i, "These are the details for choice "+i));
}
Label label = new Label();
choices.valueProperty().addListener((obs, oldItem, newItem) -> {
label.textProperty().unbind();
if (newItem == null) {
label.setText("");
} else {
label.textProperty().bind(newItem.detailsProperty());
}
});
BorderPane root = new BorderPane();
root.setCenter(label);
root.setTop(choices);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public class Item {
private final String name ;
private final StringProperty details = new SimpleStringProperty() ;
public Item(String name, String details) {
this.name = name ;
setDetails(details) ;
}
public String getName() {
return name ;
}
#Override
public String toString() {
return getName();
}
public final StringProperty detailsProperty() {
return this.details;
}
public final String getDetails() {
return this.detailsProperty().get();
}
public final void setDetails(final String details) {
this.detailsProperty().set(details);
}
}
public static void main(String[] args) {
launch(args);
}
}
In this case, there is never a need to repeat an action when the user "reselects" the same option, because the code always assures that the UI is consistent with what is selected anyway (there is necessarily nothing to do if the user selects the option that is already selected). By using bindings in the part of the UI showing the details (just a simple label in this case), we are assured that the UI stays up to date if the data changes externally. (Obviously in a real application, this may be far more complex, but the basic strategy is still exactly the same.)
On the other hand, functionality that requires an action to be repeated if the user selects the same functionality is better considered as presenting the user with a set of "actions". The appropriate controls for this are things like menus, toolbars with buttons, and MenuButtons.
An example of a set of repeatable actions is:
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class MenuButtonExample extends Application {
#Override
public void start(Stage primaryStage) {
MenuButton menuButton = new MenuButton("Items");
Label label = new Label();
Item[] items = new Item[3];
for (int i = 1 ; i <=3 ; i++) {
items[i-1] = new Item("Item "+i);
}
for (Item item : items) {
MenuItem menuItem = new MenuItem(item.getName());
menuItem.setOnAction(e -> item.setTimesChosen(item.getTimesChosen() + 1));
menuButton.getItems().add(menuItem);
}
label.textProperty().bind(Bindings.createStringBinding(() ->
Stream.of(items)
.map(item -> String.format("%s chosen %d times", item.getName(), item.getTimesChosen()))
.collect(Collectors.joining("\n")),
Stream.of(items)
.map(Item::timesChosenProperty)
.collect(Collectors.toList()).toArray(new IntegerProperty[0])));
BorderPane root = new BorderPane();
root.setCenter(label);
root.setTop(menuButton);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Item {
private final String name ;
private final IntegerProperty timesChosen = new SimpleIntegerProperty();
public Item(String name) {
this.name = name ;
}
public String getName() {
return name ;
}
#Override
public String toString() {
return getName();
}
public final IntegerProperty timesChosenProperty() {
return this.timesChosen;
}
public final int getTimesChosen() {
return this.timesChosenProperty().get();
}
public final void setTimesChosen(final int timesChosen) {
this.timesChosenProperty().set(timesChosen);
}
}
public static void main(String[] args) {
launch(args);
}
}
The idea is to set a listener on the ListView pane, that appears whenever you click on the ComboBox. The ListView instance is created once the ComboBox is first loaded in the JavaFX scene. Therefore, we add a listener on the ComboBox to check when it appears on the scene, and then through the "lookup" method we get the ListView and add a listener to it.
private EventHandler<MouseEvent> cboxMouseEventHandler;
private void initComboBox() {
ComboBox<String> comboBox = new ComboBox<String>();
comboBox.getItems().add("Item 1");
comboBox.getItems().add("Item 2");
comboBox.getItems().add("Item 3");
comboBox.sceneProperty().addListener((a,oldScene,newScene) -> {
if(newScene == null || cboxMouseEventHandler != null)
return;
ListView<?> listView = (ListView<?>) comboBox.lookup(".list-view");
if(listView != null) {
cboxMouseEventHandler = (e) -> {
Platform.runLater(()-> {
String selectedValue = (String) listView.getSelectionModel().getSelectedItem();
if(selectedValue.equals("Item 1"))
System.out.println("Item 1 clicked");
});
}; // cboxMouseEventHandler
listView.addEventFilter(MouseEvent.MOUSE_PRESSED, cboxMouseEventHandler);
} // if
});
} // initComboBox
I am still very new to Java and have been trying to figure out how to enable a text area for editing if a radio button is selected for a while now. I have been googling and reading posts on various forums, however i don;t understand what they are doing or how to do it within my program what so ever.
Here is what I have so far:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package labscheduler;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.*;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*
* #author S02105032
*/
public class FXMLLabSchedulerDocController implements Initializable {
#FXML
private TextField txtRequestorName;
#FXML
private TextField txtRequestorEmail;
#FXML
private TextField txtEventTitle;
#FXML
private TextField txtNumParticipants;
#FXML
private TextField txtEventDate;
#FXML
private TextField txtStartTime;
#FXML
private TextField txtEndTime;
#FXML
private ToggleButton togStartTime;
#FXML
private ToggleButton togEndTime;
#FXML
private CheckBox chkPrinter;
#FXML
private RadioButton rbYes;
#FXML
private RadioButton rbNo;
#FXML
private TextArea txtareaMessage;
private String requestorName;
private String requestorEmail;
private String eventTitle;
private int participants = 0;
private Date eventDate;
private Date startTime;
private Date endTime;
private String printer;
private String message;
#FXML
private void handleBtnSubmit(ActionEvent event) {
requestorName = txtRequestorName.getText();
requestorEmail = txtRequestorEmail.getText();
eventTitle = txtEventTitle.getText();
participants = Integer.parseInt(txtNumParticipants.getText());
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/YY");
try {
eventDate = sdf.parse(txtEventDate.getText());
} catch (ParseException ex) {
System.out.println("invalid date format");
}
SimpleDateFormat stdf = new SimpleDateFormat("hh:mm");
try {
startTime = stdf.parse(txtStartTime.getText());
} catch (ParseException ex) {
System.out.println("invalid start time format");
}
SimpleDateFormat etdf = new SimpleDateFormat("hh:mm");
try {
endTime = etdf.parse(txtEndTime.getText());
} catch (ParseException ex) {
System.out.println("invalid end time format");
}
if(chkPrinter.isSelected()) {
printer = "printer requested";
}
else {
printer = "no printer needed";
}
if(rbYes.isSelected() && !rbNo.isSelected()) {
txtareaMessage.setEditable(true);
message = txtareaMessage.getText();
}
else {
txtareaMessage.setEditable(false);
message = "None";
}
}
#FXML
private void handleButtonClose(ActionEvent event) {
System.out.println("Application Close!");
Platform.exit();
}
#FXML
private void handleButtonClear(ActionEvent e) {
System.out.println("Clear All Fields!");
txtRequestorName.setText("");
txtRequestorEmail.setText("");
txtEventTitle.setText("");
txtNumParticipants.setText("");
txtEventDate.setText("");
txtStartTime.setText("");
txtEndTime.setText("");
chkPrinter.setSelected(false);
rbYes.setSelected(false);
rbNo.setSelected(false);
txtareaMessage.setText("");
}
// Radio Buttons need to be set to group so only one can be selected at a time
// If Radio Btn Yes is checked, enable txt area message, else disable
// Set Toggle Buttons to toggle between AM & PM
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
When I select either of the radio buttons, it does not seem to be making the text area editable.
The state of JavaFX controls is represented by observable properties. So the RadioButton has a selectedProperty and the TextArea has a editableProperty. You can set and retrieve the values of these with the usual set/get (or set/is) methods: txtareaMessage.setEditable(rbYes.isSelected()), you can also observe them for changes:
rbYes.selectedProperty().addListener(...);
or you can bind the value of one property to the value of another. Binding essentially just registers a listener with one property and updates the other property when the observed property changes.
In your case the logic is very simple (the value of the text area's editable property should be the same as the value of the radio button's selected property), so all you need is to establish a simple binding in the initialize() method:
txtareaMessage.editableProperty().bind(rbYes.selectedProperty());
if(rbYes.isSelected() && !rbNo.isSelected()) {
txtareaMessage.setEditable(true);
message = txtareaMessage.getText();
}
else {
txtareaMessage.setEditable(false);
message = "None";
}
That segment of code is within an ActionListener for your button (handleBtnSubmit), therefore from what I understand, you need an ActionListener on your radio buttons to fire the code aforementioned.
Create an ToggleGroup like this.
final ToggleGroup group = new ToggleGroup();
Add the Radiobuttons to the "group".
RadioButton yes = new RadioButton("yes");
yes.setToggleGroup(group);
RadioButton no= new RadioButton("no");
no.setToggleGroup(group);
Check if the "yes" RadioButton is selected.
yes.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
if(yes.isSelected()){
textField.setEnabled(true);
}else{
textField.setEnabled(false);
}
}
});