Array size not setting correctly - javafx

I asked a previous question here, and got excellent feedback. I am back with one more issue in the same program. My output file is always blank, and I figured out why, but I don't know how to correct it. In getArray, I set totalEmployees to the value entered in the stage2 textField. This is supposed to be the array size declaration, but when i test the code, the array size is always set to 0, therefore giving me a blank text doc. This is because the array size is set to totalEmployees before the value is saved to totalEmployees. I am not quite sure how to go about correcting this. Here is the code that I have:
import java.io.*;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
public class companyParoll extends Application
{
private TextField tfNumOfEmployees = new TextField();
private TextField tfEmpFirstName = new TextField();
private TextField tfEmpLastName = new TextField();
private TextField tfEmpPayRate = new TextField();
private TextField tfEmpHoursWorked = new TextField();
private Button btEnterNum = new Button("Submit");
private Button btNextEmp = new Button("Add Employee");
private Button btRunReport = new Button("Run Report");
private Button btQuit = new Button("Quit");
//Declare Variables
int totalEmployees;
int index = 0;
String[] firstName = new String[totalEmployees];
String[] lastName = new String[totalEmployees];
double[] payRate = new double[totalEmployees];
double[] hoursWorked = new double[totalEmployees];
Stage stage2 = new Stage();
#Override // Override the start method in the Application class
public void start(Stage primaryStage)
{
//Create the UI
GridPane gridPane =new GridPane();
GridPane gridPane2 = new GridPane();
gridPane.setHgap(75);
gridPane.setVgap(15);
gridPane.add(new Label("Employee's First Name:"), 0, 0);
gridPane.add(tfEmpFirstName, 1, 0);
gridPane.add(new Label("Employee's Last Name:"), 0, 1);
gridPane.add(tfEmpLastName, 1, 1);
gridPane.add(new Label("Employee's Hourly Pay Rate:"), 0, 2);
gridPane.add(tfEmpPayRate, 1, 2);
gridPane.add(new Label("Hours Worked by Employee"), 0, 3);
gridPane.add(tfEmpHoursWorked, 1, 3);
gridPane.add(btNextEmp, 1, 4);
gridPane.add(btQuit, 0, 6);
gridPane.add(btRunReport, 1, 6);
//Set properties
gridPane.setAlignment(Pos.CENTER);
tfEmpFirstName.setAlignment(Pos.BOTTOM_RIGHT);
tfEmpLastName.setAlignment(Pos.BOTTOM_RIGHT);
tfEmpPayRate.setAlignment(Pos.BOTTOM_RIGHT);
tfEmpHoursWorked.setAlignment(Pos.BOTTOM_RIGHT);
GridPane.setHalignment(btQuit, HPos.LEFT);
GridPane.setHalignment(btRunReport, HPos.RIGHT);
GridPane.setHalignment(btNextEmp, HPos.RIGHT);
gridPane2.setHgap(75);
gridPane2.setVgap(15);
gridPane2.add(new Label("Enter the Number of Employees:"), 0, 0);
gridPane2.add(tfNumOfEmployees,0 ,1);
gridPane2.add(btEnterNum, 0, 2);
gridPane2.setAlignment(Pos.CENTER);
tfNumOfEmployees.setAlignment(Pos.BOTTOM_RIGHT);
GridPane.setHalignment(btEnterNum, HPos.CENTER);
btEnterNum.setOnAction(e -> getArraySize());
btRunReport.setOnAction(e -> outputReport());
btNextEmp.setOnAction(e -> addEmployeeData());
btQuit.setOnAction(e -> quitApplication());
// Create a scene and place it in the stage
Scene scene= new Scene(gridPane, 400, 250) ;
primaryStage.setTitle("Payroll Calculator"); // Set title
primaryStage.setScene(scene); // Place the scene in t he stage
primaryStage.show(); // Display the stage
//Create new window to get number of employees
Scene scene2 = new Scene(gridPane2, 200, 150);
stage2.setTitle("Number of Employees");
stage2.setScene(scene2);
stage2.show();
}
public void getArraySize()
{
totalEmployees = Integer.parseInt(tfNumOfEmployees.getText());
stage2.close();
}
public void addEmployeeData()
{
while (index < firstName.length)
{
firstName[index] = tfEmpFirstName.getText();
lastName[index] = tfEmpLastName.getText();
payRate[index] = Double.parseDouble(tfEmpPayRate.getText());
hoursWorked[index] = Integer.parseInt(tfEmpHoursWorked.getText());
index ++;
break;
}
tfEmpFirstName.clear();
tfEmpLastName.clear();
tfEmpPayRate.clear();
tfEmpHoursWorked.clear();
}
public void outputReport()
{
try
{
PrintWriter empPayroll = new PrintWriter("Payroll.txt");
double regularHours = 0;
double overtimeHours = 0;
double regularPay = 0;
double overtimePay = 0;
double totalPay = 0;
for (index = 0; index < firstName.length; index++)
{
if (hoursWorked[index] >= 40)
regularHours = 40;
else
regularHours = hoursWorked[index];
if (hoursWorked[index] > 40)
overtimeHours = hoursWorked[index] - 40;
else
overtimeHours = 0;
regularPay = (payRate[index] * regularHours);
overtimePay = ((payRate[index] * 1.5) * overtimeHours);
totalPay = regularPay + overtimePay;
empPayroll.println("\nName: " + firstName[index] + " " + lastName[index]);
empPayroll.println("Pay Rate: " + payRate[index]);
empPayroll.println("Regular Hours Worked: " + regularHours);
empPayroll.println("Overtime Hours Worked: " + overtimeHours);
empPayroll.println("Regular Pay: " + regularPay);
empPayroll.println("Overtime Pay: " + overtimePay);
empPayroll.println("Total Gross Pay: " + totalPay);
}
empPayroll.close();
}
catch (IOException exp)
{
exp.printStackTrace();
}
System.out.println(firstName.length);
}
public void quitApplication()
{
Platform.exit(); //Close application
}
public static void main(String[] args)
{
Application.launch();
}
}

It looks like you're only using "totalEmployees" to instantiate those arrays.
Assuming that those arrays are not used anytime before the user clicks btEnterNum (Which is important because trying to do so would result in a Null Pointer Exception),
you could just declare the arrays, and instantiate them in your getArraySize() method.
private String[] firstName;
private String[] lastName;
private double[] payRate;
private double[] hoursWorked;
public void getArraySize() {
totalEmployees = Integer.parseInt(tfNumOfEmployees.getText());
firstName = new String[totalEmployees];
lastName = new String[totalEmployees];
payRate = new double[totalEmployees];
hoursWorked = new double[totalEmployees];
stage2.close();
}
On the other hand, however, if you do need to use those arrays first, then you could try an ArrayList instead. HTH

Related

JavaFX - Check the position of a label based on a mouse click

I try to write a code that find the label on which one have clicked.
Using an event listener, I got the positions of the event using getX() and getY().
However, I cannot find the adequate methods for the label positions in order to compare them.
Below is my code, and its ouput.
public class Beta extends Application {
final Label[] answerLabel = new Label[4];
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setGridLinesVisible(true);
final int numCols = 7 ;
final int numRows = 12 ;
//final Label[] answerLabel = new Label[4];
for (int i = 0; i < numCols; i++) {
ColumnConstraints colConst = new ColumnConstraints();
colConst.setPercentWidth(100.0 / numCols);
root.getColumnConstraints().add(colConst);
}
for (int i = 0; i < numRows; i++) {
RowConstraints rowConst = new RowConstraints();
rowConst.setPercentHeight(100.0 / numRows);
root.getRowConstraints().add(rowConst);
}
for(int i = 0; i<4; i++){
answerLabel[i] = new Label();
answerLabel[i].setMaxWidth(Double.MAX_VALUE);
answerLabel[i].setMaxHeight(Double.MAX_VALUE);
answerLabel[i].setStyle("-fx-background-color: blue;-fx-font-size: 7pt;-fx-padding: 0;");
answerLabel[i].setPadding(new Insets(10));
answerLabel[i].setCursor(Cursor.HAND);
root.add(answerLabel[i], 3, i +5, 1, 1);
answerLabel[i].setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
answerLabelPressed(e);
}
});
}
primaryStage.setScene(new Scene(root, 900, 500));
primaryStage.show();
}
private void answerLabelPressed(MouseEvent e)
{
int labelSelected;
double px = e.getX();
double py = e.getY();
System.out.println("px = " + px + " py = " + py);
for (labelSelected = 0; labelSelected < 4; labelSelected++)
{
System.out.println("answerLabel[labelSelected].getLayoutX() = " + answerLabel[labelSelected].getLayoutX());
System.out.println("answerLabel[labelSelected].getLayoutY() = " + answerLabel[labelSelected].getLayoutY());
}
}
public static void main(String[] args) {
launch(args);
}
}
px = 42.0 py = 7.0
answerLabel[labelSelected].getLayoutX() = 386.0
view.answerLabel[labelSelected].getLayoutY() = 208.0
answerLabel[labelSelected].getLayoutX() = 386.0
view.answerLabel[labelSelected].getLayoutY() = 250.0
answerLabel[labelSelected].getLayoutX() = 386.0
view.answerLabel[labelSelected].getLayoutY() = 292.0
answerLabel[labelSelected].getLayoutX() = 386.0
view.answerLabel[labelSelected].getLayoutY() = 333.0
Upadate: The main purpose was to find/check the equivalent JavaFX methods of those used in Java Swing.
An alternative and better algorithm beeing as one can read in most popular Java books :
MouseListener ml = new MouseListener() {
public void mouseClicked(MouseEvent e) {
report("mouseClicked", e.paramString());
}
In Java Swing, one should read :
Point p = e.getComponent().getLocation();
System.out.println("px = " + p.getX() + " py = " + p.getY());
for (labelSelected = 0; labelSelected < 4; labelSelected++)
{
System.out.println("answerLabel[labelSelected].getX() = " + answerLabel[labelSelected].getX());
System.out.println("answerLabel[labelSelected].getY() = " + answerLabel[labelSelected].getY());
}
I try to write a code that find the label on which one have clicked.
You create four labels, and you create a listener for each label. Each listener is only registered with one label.
So there is no need to get your hands dirty with the coordinates of the click (the event handling mechanism has already done all of that for you, when it decided to which node to dispatch the event). Just reference the label that was clicked:
public class Beta extends Application {
final Label[] answerLabel = new Label[4];
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setGridLinesVisible(true);
final int numCols = 7 ;
final int numRows = 12 ;
for (int i = 0; i < numCols; i++) {
ColumnConstraints colConst = new ColumnConstraints();
colConst.setPercentWidth(100.0 / numCols);
root.getColumnConstraints().add(colConst);
}
for (int i = 0; i < numRows; i++) {
RowConstraints rowConst = new RowConstraints();
rowConst.setPercentHeight(100.0 / numRows);
root.getRowConstraints().add(rowConst);
}
for(int i = 0; i<4; i++){
answerLabel[i] = new Label();
answerLabel[i].setMaxWidth(Double.MAX_VALUE);
answerLabel[i].setMaxHeight(Double.MAX_VALUE);
answerLabel[i].setStyle("-fx-background-color: blue;-fx-font-size: 7pt;-fx-padding: 0;");
answerLabel[i].setPadding(new Insets(10));
answerLabel[i].setCursor(Cursor.HAND);
root.add(answerLabel[i], 3, i +5, 1, 1);
Label currentLabel = answerLabel[i];
int currentIndex = i ;
answerLabel[i].setOnMouseClicked(event -> {
System.out.println("Clicked on label "+currentIndex);
// just for demo: in real life use external stylesheets
// and pseudoclasses, etc.
for (Label label : answerLabel) {
label.setStyle("-fx-background-color: blue;-fx-font-size: 7pt;-fx-padding: 0;");
}
currentLabel.setStyle("-fx-background-color: gold;-fx-font-size: 7pt;-fx-padding: 0;");
});
}
primaryStage.setScene(new Scene(root, 900, 500));
primaryStage.show();
}
}
It is not necessary to manually compute which node the mouse clicked on. That calculation is already done for you by the framework. That's how the framework knows which event handlers to invoke. If you simply add a unique handler to each node, then when that handler is invoked only that node could be the source. This is demonstrated in #James_D's answer.
However, if you want to manually compute which node was clicked (e.g., for fun or just for learning purposes), then here is a runnable example:
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Border;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
var labels = IntStream.range(0, 12)
.mapToObj(this::createLabel)
.toArray(Label[]::new);
var grid = new GridPane();
grid.setPadding(new Insets(20));
grid.setHgap(20);
grid.setVgap(20);
grid.setOnMouseClicked(e -> {
var clickedOnLabel = getClickedOnLabel(labels, e);
if (clickedOnLabel == null) {
System.out.println("You did not click on a label!");
} else {
System.out.printf("You clicked on a label: '%s'%n", clickedOnLabel.getText());
}
});
int i = 0;
for (int col = 0; col < 4; col++) {
for (int row = 0; row < 3; row++) {
grid.add(labels[i++], col, row);
}
}
primaryStage.setScene(new Scene(grid));
primaryStage.show();
}
private Label getClickedOnLabel(Label[] labels, MouseEvent event) {
for (var label : labels) {
var bounds = label.localToScene(label.getBoundsInLocal());
if (bounds.contains(event.getSceneX(), event.getSceneY())) {
return label;
}
}
return null;
}
private Label createLabel(int n) {
var label = new Label(String.format("Label #%02d", n));
label.setCursor(Cursor.HAND);
label.setPadding(new Insets(5));
label.setFont(Font.font("Monospaced", 15.0));
label.setBorder(Border.stroke(Color.BLACK));
return label;
}
}
The important part, the part which computes which label was clicked on, is here:
private Label getClickedOnLabel(Label[] labels, MouseEvent event) {
for (var label : labels) {
var bounds = label.localToScene(label.getBoundsInLocal());
if (bounds.contains(event.getSceneX(), event.getSceneY())) {
return label;
}
}
return null;
}
It gets the bounds of each Label in the scene's coordinate space, and then tests if the mouse's location—also in the scene's coordinate space—is contained within those bounds. You can use whatever coordinate space you like (e.g., the screen's, the grid pane's, the label's, etc.), as long as you use the same one for both the label's bounds and the mouse's location. Note the mouse's local coordinates (i.e., getX() and getY()) are in the source node's coordinate space. The source node is the node that the currently-being-invoked handler was registered with for the specific event currently being processed (the GridPane in the above example).
But again, for any "real" code, I strongly recommend you use the solution in #James_D's answer.

Detecting button click of button added to javafx listview

I am very new to Java so please be patient with me. I have successfully added buttons, labels and even a progress bar to a listview cell. I need to be able to detect when one of the buttons has been clicked. Adding controls to listview content I managed to get from a couple of posts here the code i am using is shown below
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ProgressBar;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class ListViewDemo extends Application {
public static class lvCell extends VBox {
Label labelName = new Label();
Label labelPath = new Label();
Label labelElapse = new Label();
Button buttonPlayPause = new Button();
Button buttonStop = new Button();
ImageView ivStop = new ImageView();
ImageView ivPlay = new ImageView();
Pane buttonSpacer = new Pane();
Pane progressBarSpacer = new Pane();
HBox hbDetail = new HBox();
HBox hbProgress = new HBox();
ProgressBar pbProgress = new ProgressBar();
File filePlay;
File fileStop;
double prefWidth = 10;
double prefHeight = 10;
lvCell(String labelText) {
super();
labelName.setText(labelText);
labelName.setMaxWidth(Double.MAX_VALUE);
labelPath.setMaxWidth(0);
labelPath.setText("Path");
pbProgress.setMaxWidth(Double.MAX_VALUE);
HBox.setHgrow(labelName, Priority.ALWAYS);
HBox.setHgrow(pbProgress, Priority.ALWAYS);
HBox.setMargin(labelName, new Insets(5, 0, 0, 0));
HBox.setMargin(pbProgress, new Insets(0, 0, 0, 0));
labelPath.setVisible(false);
buttonSpacer.setPrefSize(prefWidth, prefHeight);
labelElapse.setPrefSize(50, prefHeight);
labelElapse.setText("Time");;
progressBarSpacer.setPrefSize(prefWidth * 6, prefHeight);
filePlay = new File("src/image/play.png");
fileStop = new File("src/image/stop.png");
Image imagePlay = new Image(filePlay.toURI().toString());
Image imageStop = new Image(fileStop.toURI().toString());
ivPlay.setImage(imagePlay);
ivStop.setImage(imageStop);
ivPlay.setFitHeight(prefHeight);
ivPlay.setFitWidth(prefWidth);
ivStop.setFitHeight(prefHeight);
ivStop.setFitWidth(prefWidth);
buttonPlayPause.setGraphic(ivPlay);
buttonStop.setGraphic(ivStop);
buttonPlayPause.setMaxSize(prefWidth, prefHeight);
buttonStop.setMaxSize(prefWidth, prefHeight);
pbProgress.setMaxHeight(2);
pbProgress.setPrefHeight(2);
hbDetail.getChildren().addAll(buttonPlayPause, buttonStop, buttonSpacer, labelName, labelPath);
hbProgress.getChildren().addAll(progressBarSpacer, pbProgress, labelElapse);
this.getChildren().addAll(hbDetail, hbProgress);
}
}
public Parent createContent() {
BorderPane layout = new BorderPane();
List < lvCell > list = new ArrayList < > ();
for (int i = 0; i < 10; i++) {
list.add(new lvCell("Item " + i));
}
ListView < lvCell > listView = new ListView < lvCell > ();
ObservableList < lvCell > myObservableList = FXCollections.observableList(list);
listView.setItems(myObservableList);
layout.setCenter(listView);
return layout;
}
#Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setWidth(300);
stage.setHeight(200);
stage.show();
}
public static void main(String args[]) {
launch(args);
}
}
The screen looks like this:
Any help will be greatly appreciated.
Thanks in advance, and wishing you a peaceful journey.
Yas
This is not a class well designed to put into a ListView. An object used as item in a ListView should contain data; the ListCell implementation produced by the cellFactory is responsible for determining the visual representation of the data in the ListView. This way you avoid the creation of nodes for every object reducing the memory footprint, which is exactly what ListView is designed for.
Simplified example
The data here contains just the progress and some text; it's displayed in a ProgressBar and the text of the cell; an additional button in the cell allows increasing the progress by 0.25 for each click and removing any items reaching a progress of 1.
Data class
public class Data {
private final DoubleProperty progress = new SimpleDoubleProperty();
private final String text;
public Data(String text) {
this.text = text;
}
public double getProgress() {
return progress.get();
}
public void setProgress(double value) {
progress.set(value);
}
public String getText() {
return text;
}
public ObservableValue<? extends Number> progressProperty() {
return progress;
}
}
ListView code
ListView<Data> listView = new ListView<>(someData);
listView.setCellFactory(l -> new ListCell<Data>() {
private final ProgressBar progressBar = new ProgressBar();
private final Button button = new Button("increase");
private final HBox content = new HBox(progressBar, button);
{
button.setOnAction(evt -> {
Data item = getItem();
int index = getIndex();
double progress = item.getProgress() + 0.25;
item.setProgress(progress);
if (progress >= 1) {
getListView().getItems().remove(index);
}
});
}
#Override
protected void updateItem(Data item, boolean empty) {
super.updateItem(item, empty);
progressBar.progressProperty().unbind();
if (item == null) {
setGraphic(null);
setText("");
} else {
setGraphic(content);
setText(item.getText());
progressBar.progressProperty().bind(item.progressProperty());
}
}
});

gridpane javafx clickable cells that get toggled and untoggled

I am trying to create a gridpane that is toggled/untoggled as the user clicks on specific cells. For example, when the user clicks on a cell with the content "*", I would like the content of that specific cell to be changed into a blank cell " ". Similarly, if the user clicks on a cell with a blank content " ", I would like the content of that cell to be changed into a cell with the content "*".
Basically, I am starting out with a grid that is partly input as follows:
My gridpane is initially input as follows, I am keeping track of a matrix of booleans that represents whether there should be a "*" in one cell of the matrix. If there is a "*" in cell [i, j] of the gridpane, then the value of matrix[i,j] should be true, otherwise it should be false.
boolean matrix[][] = new boolean[StateList.size()+1][RequirementList.size()+1];
for( InstanceArtifact li: ListOfLinks) {
int y=1;
for(InstanceArtifact re: RequirementList) {
int x=1;
for(InstanceArtifact state: StateList) {
if(li.getPropertyValue("linksource").equals(re) && li.getPropertyValue("linktarget").equals(state)) {
link= new Label(" * ");
//tick in cell (1,1)
grid.add(link, y, x);
matrix[x][y]= true;
}
else {
link= new Label(" ");
//tick in cell (1,1)
grid.add(link, y, x);
}
x++;
}
y++;
}
}
}
What I would like to do is toggle/untoggle the stars, this is what I am trying to do with the code below, as we are clicking on a cell containing "*", meaning that matrix[i][j]=true, I am removing the corresponding label in the grid and I am adding a new label with an empty text. I also do the same thing in the opposite situation in which the label text is blank and I need to replace it with a label containing a star.
grid.getChildren().forEach(element -> {
element.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
int matrixX= GridPane.getRowIndex(element);
int matrixY= GridPane.getColumnIndex(element);
if(element!=null && matrixX!=0 && matrixY!=0) {
System.out.println("matrixX: "+matrixX+" matrixY: "+matrixY);
System.out.println("matrixY: "+matrixY+" "+ matrix[matrixX][matrixY]);
if(matrix[matrixX][matrixY]==true && matrixX!=0 && matrixY!=0) {
System.out.println("HEY I AM HERE FIRSTTTTTTTTT");
Node newnode= new Label(" ");
GridPane.clearConstraints(element);
// grid.getChildren().remove(element);
grid.add(newnode, matrixY, matrixX);
matrix[matrixX][matrixY]=false;
/*for(int l=0; l<RequirementList.size(); l++) {
for(int p=0; p<StateList.size(); p++) {
System.out.println(l + " "+p +" "+matrix[l][p]);
}
}*/
//grid.add(mynode, matrixY+1, matrixX+1, 1, 1);
}
else if(matrix[matrixX][matrixY]==false && matrixX!=0 && matrixY!=0){
System.out.println("HEY I AM HERE SECONDDDDDDD ");
/* for(int l=0; l<RequirementList.size(); l++) {
for(int p=0; p<StateList.size(); p++) {
System.out.println(l + " "+p +" "+matrix[l][p]);
}
}*/
Node falsenode= new Label(" * ");
GridPane.clearConstraints(element);
// grid.getChildren().remove(element);
grid.add(falsenode, matrixY, matrixX);
matrix[matrixX][matrixY]=true;
}
// System.out.println("Row: " + GridPane.getRowIndex(element));
// System.out.println("Column: " + GridPane.getColumnIndex(element));
}
}
});
});
My code is not behaving as expected, I would like the cell to be toggled/untoggled whenever the user clicks on a cell, the code is executed only the first time the user clicks on a given cell, if the user clicks on the same cell multiple times (more than once), then nothing happens.
Also, the line of code in which I am trying to remove a label is not working:
grid.getChildren().remove(element);
This could be better served with ToggleButton. Comments in code.
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
/**
*
* #author Sedrick
*/
public class JavaFXApplication60 extends Application {
#Override
public void start(Stage primaryStage) {
//Start create GUI
Label lblRequirement11 = new Label("Requirement1");
Label lblRequirement12 = new Label("Requirement2");
Label lblRequirement13 = new Label("Requirement3");
GridPane.setConstraints(lblRequirement11, 1, 0);
GridPane.setConstraints(lblRequirement12, 2, 0);
GridPane.setConstraints(lblRequirement13, 3, 0);
Label lblState1 = new Label("State1");
ToggleButton toggleButton11 = new ToggleButton();
toggleButton11.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton12 = new ToggleButton();
toggleButton12.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton13 = new ToggleButton();
toggleButton13.setMaxWidth(Double.MAX_VALUE);
GridPane.setConstraints(lblState1, 0, 1);
GridPane.setConstraints(toggleButton11, 1, 1);
GridPane.setConstraints(toggleButton12, 2, 1);
GridPane.setConstraints(toggleButton13, 3, 1);
Label lblState2 = new Label("State2");
ToggleButton toggleButton21 = new ToggleButton();
toggleButton21.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton22 = new ToggleButton();
toggleButton22.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton23 = new ToggleButton();
toggleButton23.setMaxWidth(Double.MAX_VALUE);
GridPane.setConstraints(lblState2, 0, 2);
GridPane.setConstraints(toggleButton21, 1, 2);
GridPane.setConstraints(toggleButton22, 2, 2);
GridPane.setConstraints(toggleButton23, 3, 2);
Label lblState3 = new Label("State3");
ToggleButton toggleButton31 = new ToggleButton();
toggleButton31.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton32 = new ToggleButton();
toggleButton32.setMaxWidth(Double.MAX_VALUE);
ToggleButton toggleButton33 = new ToggleButton();
toggleButton33.setMaxWidth(Double.MAX_VALUE);
GridPane.setConstraints(lblState3, 0, 3);
GridPane.setConstraints(toggleButton31, 1, 3);
GridPane.setConstraints(toggleButton32, 2, 3);
GridPane.setConstraints(toggleButton33, 3, 3);
GridPane root = new GridPane();
root.setVgap(5);
root.setHgap(5);
root.getChildren().addAll(lblRequirement11, lblRequirement12, lblRequirement13);
root.getChildren().addAll(lblState1, toggleButton11, toggleButton12, toggleButton13);
root.getChildren().addAll(lblState2, toggleButton21, toggleButton22, toggleButton23);
root.getChildren().addAll(lblState3, toggleButton31, toggleButton32, toggleButton33);
//End create GUI
//Start create ToggleButtons' event handlers.
List<ToggleButton> toggleButtonList = new ArrayList();
toggleButtonList.add(toggleButton11);
toggleButtonList.add(toggleButton12);
toggleButtonList.add(toggleButton13);
toggleButtonList.add(toggleButton21);
toggleButtonList.add(toggleButton22);
toggleButtonList.add(toggleButton23);
toggleButtonList.add(toggleButton31);
toggleButtonList.add(toggleButton32);
toggleButtonList.add(toggleButton33);
for(ToggleButton tempToggleButton : toggleButtonList)
{
tempToggleButton.setOnAction(actionEvent -> {
if(tempToggleButton.isSelected())
{
tempToggleButton.setText("*");
}
else
{
tempToggleButton.setText("");
}
});
}
////End create ToggleButtons' event handlers.
Scene scene = new Scene(root, 400, 300);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

Adding multiple nodes to vbox javafx

I am new in JavaFx and I spend too much time trying to put radio button + textfield dynamically. After typing a number, I want to display my radio buttons and my TextFields in that way (blue and red ones)
But I got this:
I tried with vbox, hbox, both of them, but it did not work!
Can anyone figure out the problem in my code please!!! Thanks for your help
RadioButton[] btn = new RadioButton[100]; //our Collection to hold newly created Buttons
TextField[] xlist = new TextField[100]; //our Collection to hold newly created Buttons
TextField[] ylist = new TextField[100];
final ToggleGroup grpBtn = new ToggleGroup();
#FXML
private Group noeuds;
#FXML
private VBox vb2;
#FXML
private HBox hb2;
#FXML
public void addBtn(int i, RadioButton[] btn) {
btn[i] = new RadioButton();
btn[i].setText(String.valueOf(i + 1));
btn[i].setToggleGroup(grpBtn);
btn[i].setSelected(true);
btn[i].setTranslateX(-5);
btn[i].setTranslateY(-340);
btn[i].setPadding(new Insets(0, 0, 20, 20));
vb2.getChildren().add(btn[i]);
}
#FXML
public void addX(int i, TextField[] xlist) {
xlist[i] = new TextField();
xlist[i].setTranslateX(-80);
xlist[i].setTranslateY(40);
xlist[i].setStyle("-fx-background-color: red;");
xlist[i].setPrefSize(30, 30);
xlist[i].setTooltip(new Tooltip("X coordinate of " + (i + 1)));
hb2.getChildren().add(xlist[i]);
}
#FXML
public void addY(int i, TextField[] ylist) {
ylist[i] = new TextField();
ylist[i].setTranslateX(-78);
ylist[i].setTranslateY(40);
ylist[i].setStyle("-fx-background-color: blue;");
ylist[i].setPrefSize(30, 30);
ylist[i].setTooltip(new Tooltip("Y coordinate of" + (i + 1)));
hb2.getChildren().add(ylist[i]);
}
public void initialize(URL url, ResourceBundle rb) {
//some code
for (int i = 0; i < Integer.parseInt(nodeID.getText()); i++) {
addBtn(i, btn);
// System.out.println("jjjj"+btn.length);
addX(i, xlist);
// System.out.println("mmmm"+xlist.length);
addY(i, ylist);
}
}
This little app might help give you a boost. Read over the code and try to get an understanding. I tried to make comments in the code.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication7 extends Application {
#Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
VBox vbox1 = new VBox();
vbox1.setSpacing(5);//Set vbox spacing
//Handles the number of row to be added to the vbox
for(int i = 0; i < 4; i++)
{
vbox1.getChildren().add(addNewRow(i));
}
root.getChildren().add(vbox1);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
//Method creates all the nodes for a new row.
HBox addNewRow(int rowNumber)
{
//Create nodes and adding correct spaceing
HBox hbox = new HBox();
hbox.setSpacing(5);
RadioButton radioButton = new RadioButton();
radioButton.setPrefHeight(25);
TextField textField = new TextField();
textField.setPrefWidth(40);
Label label = new Label(Integer.toString(rowNumber + 1));
label.setPrefHeight(25);
HBox trailingHBox = new HBox();
trailingHBox.setSpacing(5);
hbox.getChildren().addAll(radioButton, textField, label, trailingHBox);
//Event handler on textfield. Add right about of trailing textfields
textField.setOnKeyReleased((event)->{
if(textField.getText().trim().length() > 0 && Integer.parseInt(textField.getText()) > 0)//If textfield has some value greater than zero. I didn't catch for non integers
{
int tempInt = Integer.parseInt(textField.getText());
//clear trailingHBox so that new Trailing hbox can be added
if(trailingHBox.getChildren().size() > 0)
{
trailingHBox.getChildren().clear();
}
//add the correct number of textFields.
for(int i = 0; i < tempInt - 1; i++)
{
TextField tempTextField = new TextField();
tempTextField.setPrefWidth(20);
trailingHBox.getChildren().add(tempTextField);
}
//add the blue and red textfields
TextField textFieldBlue = new TextField();
textFieldBlue.setPrefWidth(40);
textFieldBlue.setStyle("-fx-background-color: BLUE");
TextField textFieldRed = new TextField();
textFieldRed.setPrefWidth(40);
textFieldRed.setStyle("-fx-background-color: RED");
trailingHBox.getChildren().addAll(textFieldBlue, textFieldRed);
}
else{
trailingHBox.getChildren().clear();//clear traingHbox if it's has no value
}
});
return hbox;
}
}

ScrollBar within custom Alert box not working JavaFX

Is there an easy way to put a scroll bar in an Alert box and have it actually scroll? I'm adding a grid pane to the scroll pane. While the Alert box is active, I'm adding and removing content as the user requests. Unfortunately, there is a limit to ho much I can add because the Alert box grows beyond the screen height. Hence the reason for a scroll pane. The problem is, it doesn't seem to think it needs to scroll even though the content is below the screen
I've tried a bunch of things, but each time the scroll bars grow with the scroll pane. I even tried a custom ScrollPane as suggested by James_D. Still not luck.
Any help would be awesome!
Here is the code for the custom Alert box
import java.util.ArrayList;
import java.util.List;
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XmlVisitor.TextPredictor;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.DialogPane;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
public class SettingsChangeWindow extends Alert {
public enum SETTING_TYPE {SINGLE, MULTIPLE};
private SETTING_TYPE type = null;
private IndexedGridPane parentGrid;
private SettingBean bean;
private DialogPane parentPane;
public SettingsChangeWindow(SettingBean bean) {
super(AlertType.CONFIRMATION);
this.bean = bean;
this.type = bean.getType();
SizeableScrollPane scroll = new SizeableScrollPane();
scroll.setHbarPolicy(ScrollBarPolicy.ALWAYS);
scroll.setVbarPolicy(ScrollBarPolicy.ALWAYS);
scroll.setFitToHeight(true);
scroll.setFitToWidth(true);
parentGrid = new IndexedGridPane();
scroll.setContent(parentGrid);
this.parentPane = getDialogPane();
setResizable(true);
if(type == SETTING_TYPE.SINGLE){
FriendlyVBox vbox = new FriendlyVBox();
setTitle("Change " + bean.getName());
setHeaderText("Change the " + bean.getName() + " value by changing the value in the box");
parentGrid.setPadding(new Insets(20, 150, 0, 10));
vbox.getChildren().addAll(new Label(bean.getName()), new AutoTextBox(bean.getValue()));
parentGrid.add(vbox, 0, 0);
}else{
setTitle("Change " + bean.getName());
String header = "Change the " + bean.getName() + " value by changing the value in the box\n";
header += "You may add and delete value sets (may require resizing)";
setHeaderText(header);
parentGrid.add(new AddButton(), 1, 0);
parentGrid.add(new RemoveButton(), 2, 0);
addMultipleValues();
}
this.parentPane.setContent(scroll);
// parentPane.setMinHeight(GridPane.USE_PREF_SIZE);
// parentPane.setMinWidth(GridPane.USE_PREF_SIZE);
// getDialogPane().getChildren().stream().forEach(node -> ((Label)node).setMinHeight(Region.USE_PREF_SIZE));
}
public SettingBean getValue(){
return bean;
}
private void addMultipleValues(){
List<Object> values = bean.getChildren();
if(bean.getName().equals("TSPAddressPostal") || bean.getName().equals("SchemeOperatorAddressPostal")){
for(Object addr : values){
PhysicalAddressBean address = (PhysicalAddressBean)addr;
addPhysicalAddress(address);
}
}else{
for(Object uri : values){
addURI((String)uri);
}
}
}
public void saveValue(){
if(type == SETTING_TYPE.SINGLE){
List<Node> children = parentGrid.getChildren();
for(Node child : children){
if(child instanceof FriendlyVBox){
// cast to FriendlyVBox
String value = ((FriendlyVBox)child).getTextField().getText();
this.bean.setValue(value);
}
}
}else{
saveMultipleValues();
}
}
/**
* For values in XML that can have multiple child nodes
*/
private void saveMultipleValues(){
switch(bean.getName()){
case "TSPAddressPostal" :
savePostalAddress();
break;
case "SchemeOperatorAddressPostal":
savePostalAddress();
break;
default:
saveURI();
break;
}
}
/**
* If the setting bean is encapsulating a list of physical address
* (when the name is: PostalAddress) populate via predefined structure
*/
private void savePostalAddress(){
List<Object> addresses = new ArrayList<>();
List<Node> children = parentGrid.getChildren();
for(Node child : children){
if(child instanceof IndexedGridPane){
IndexedGridPane pane = (IndexedGridPane) child;
PhysicalAddressBean add = new PhysicalAddressBean();
// each address attribute in the order listed in Trust List XML
add.setStreetAddress(((FriendlyVBox)pane.get(0, 1)).getTextField().getText());
add.setLocality(((FriendlyVBox)pane.get(0, 2)).getTextField().getText());
add.setPostalCode(((FriendlyVBox)pane.get(0, 3)).getTextField().getText());
add.setCountryName(((FriendlyVBox)pane.get(0, 4)).getTextField().getText());
// add address bean to list
addresses.add(add);
}
}
bean.setChildren(addresses);
}
/**
* used to store any values in the XML that can have multiple child URI values
*/
private void saveURI(){
List<Object> uris = new ArrayList<>();
List<Node> children = parentGrid.getChildren();
for(Node child : children){
if(child instanceof FriendlyVBox){
FriendlyVBox vBox = (FriendlyVBox) child;
uris.add(vBox.getTextField().getText());
}
}
bean.setChildren(uris);
}
private void addURI(String uri){
int newSlot = parentGrid.getRowCount();
FriendlyVBox vBox = new FriendlyVBox();
vBox.getChildren().addAll(new Label("\n" + bean.getName()), new AutoTextBox(""));
parentGrid.add(vBox, 0, newSlot);
}
private void addPhysicalAddress(){
int newSlot = parentGrid.getRowCount();
IndexedGridPane pane = new IndexedGridPane();
Label label = new Label("\nPostal Address");
pane.add(label, 0, 0);
label.setFont(Font.font("system", FontWeight.BOLD, 12));
FriendlyVBox postal = new FriendlyVBox();
postal.getChildren().addAll(new Label("Street Address"), new AutoTextBox(""));
FriendlyVBox local = new FriendlyVBox();
local.getChildren().addAll(new Label("Locale"), new AutoTextBox(""));
FriendlyVBox postalCode = new FriendlyVBox();
postalCode.getChildren().addAll(new Label("Postal Code"), new AutoTextBox(""));
FriendlyVBox country = new FriendlyVBox();
country.getChildren().addAll(new Label("Country Name"), new AutoTextBox(""));
pane.add(postal, 0, 1);
pane.add(local, 0, 2);
pane.add(postalCode, 0, 3);
pane.add(country, 0, 4);
parentGrid.add(pane, 0, newSlot);
}
private void addPhysicalAddress(PhysicalAddressBean address){
int newSlot = parentGrid.getRowCount();
IndexedGridPane pane = new IndexedGridPane();
Label label = new Label("\nPostal Address");
pane.add(label, 0, 0);
label.setFont(Font.font("system", FontWeight.BOLD, 12));
FriendlyVBox street = new FriendlyVBox();
street.getChildren().addAll(new Label("Street Address"), new AutoTextBox(address.getStreetAddress()));
FriendlyVBox local = new FriendlyVBox();
local.getChildren().addAll(new Label("Locale"), new AutoTextBox(address.getLocality()));
FriendlyVBox postalCode = new FriendlyVBox();
postalCode.getChildren().addAll(new Label("Postal Code"), new AutoTextBox(address.getPostalCode()));
FriendlyVBox country = new FriendlyVBox();
country.getChildren().addAll(new Label("Country Name"), new AutoTextBox(address.getCountryName()));
pane.add(street, 0, 1);
pane.add(local, 0, 2);
pane.add(postalCode, 0, 3);
pane.add(country, 0, 4);
parentGrid.add(pane, 0, newSlot);
}
private class IndexedGridPane extends GridPane{
public Node get(final int row, final int column) {
Node result = null;
ObservableList<Node> childrens = super.getChildren();
for (Node node : childrens) {
if(super.getRowIndex(node) == row && super.getColumnIndex(node) == column) {
result = node;
break;
}
}
return result;
}
public int getRowCount() {
int numRows = getRowConstraints().size();
for (int i = 0; i < getChildren().size(); i++) {
Node child = getChildren().get(i);
if (child.isManaged()) {
Integer rowIndex = GridPane.getRowIndex(child);
if(rowIndex != null){
numRows = Math.max(numRows,rowIndex+1);
}
}
}
return numRows;
}
}
private class AutoTextBox extends TextField{
public AutoTextBox(String contents){
setMinWidth(Region.USE_PREF_SIZE);
setMaxWidth(Region.USE_PREF_SIZE);
textProperty().addListener(new AutoAdjustText());
setText(contents);
}
private class AutoAdjustText implements ChangeListener<String>{
#Override
public void changed(ObservableValue<? extends String> ov,
String prevText, String currText) {
Platform.runLater(() -> {
Text text = new Text(currText);
text.setFont(getFont()); // Set the same font, so the size is the same
double width = text.getLayoutBounds().getWidth() // This big is the Text in the TextField
+ getPadding().getLeft() + getPadding().getRight() // Add the padding of the TextField
+ 2d; // Add some spacing
setPrefWidth(width); // Set the width
positionCaret(getCaretPosition()); // If you remove this line, it flashes a little bit
});
}
}
}
private class FriendlyVBox extends VBox{
public TextField getTextField(){
List<Node> children = getChildren();
for(Node child : children){
if(child instanceof TextField){
return (TextField)child;
}
}
return null;
}
}
private class AddButton extends Button{
public AddButton(){
setText("Add+");
onActionProperty().set(new AddValue());
}
private class AddValue implements EventHandler<ActionEvent>{
#Override
public void handle(ActionEvent event) {
if(bean.getName().equals("TSPAddressPostal") || bean.getName().equals("SchemeOperatorAddressPostal")){
addPhysicalAddress();
}else{
addURI("Add URI here");
// parentPane.setContent(parentGrid);
}
parentPane.getScene().getWindow().sizeToScene();
}
}
}
private class RemoveButton extends Button{
public RemoveButton(){
setText("Remove");
onActionProperty().set(new RemoveValue());
}
private class RemoveValue implements EventHandler<ActionEvent>{
#Override
public void handle(ActionEvent event) {
int rowCount = parentGrid.getRowCount();
parentGrid.getChildren().remove(rowCount);
parentPane.getScene().getWindow().sizeToScene();
}
}
}
private class SizeableScrollPane extends ScrollPane{
public SizeableScrollPane() {
viewportBoundsProperty().addListener(new Resizer());
hvalueProperty().addListener(new Resizer());
vvalueProperty().addListener(new Resizer());
}
private class Resizer implements ChangeListener<Object> {
#Override
public void changed(ObservableValue<? extends Object> observable, Object oldValue, Object newValue) {
double hmin = getHmin();
double hmax = getHmax();
double hvalue = getHvalue();
double contentWidth = getContent().getLayoutBounds().getWidth();
double viewportWidth = getViewportBounds().getWidth();
double hoffset =
Math.max(0, contentWidth - viewportWidth) * (hvalue - hmin) / (hmax - hmin);
double vmin = getVmin();
double vmax = getVmax();
double vvalue = getVvalue();
double contentHeight = getContent().getLayoutBounds().getHeight();
double viewportHeight = getViewportBounds().getHeight();
double voffset =
Math.max(0, contentHeight - viewportHeight) * (vvalue - vmin) / (vmax - vmin);
System.out.printf("Offset: [%.1f, %.1f] width: %.1f height: %.1f %n",
hoffset, voffset, viewportWidth, viewportHeight);
}
}
}
}
I feel stupid.
if you comment out the lines in the constructor:
scroll.setHbarPolicy(ScrollBarPolicy.ALWAYS);
scroll.setVbarPolicy(ScrollBarPolicy.ALWAYS);
scroll.setFitToHeight(true);
scroll.setFitToWidth(true);
And you comment out the lines in the button listeners:
parentPane.getScene().getWindow().sizeToScene();
All is good in the world. You don't even need a custom ScrollPane, it works as expected. I hope this helps someone else

Resources