Save/Load editable Fall tree in javafx - javafx

i have a editable fall tree which i want to save and load here is my code
public class Muddassir extends Application
{
private BorderPane root;
TreeView<String> tree;
TreeItem<String> module,unite,translateA ,translateB,rotate;
#Override
public void start(Stage primaryStage) throws Exception
{
root = new BorderPane();
root.setLeft(getLeftHBox());
root.setTop(getTop());
Scene scene = new Scene(root, 900, 500);
primaryStage.setTitle("BorderPane");
primaryStage.setScene(scene);
primaryStage.show();
}
private VBox getLeftHBox()
{
TreeItem<String> rootnode = new TreeItem<String>("Library");
rootnode.setExpanded(true);
module = makeBranch("module",rootnode);
makeBranch("Parameter X",module);
unite = makeBranch("unite",module);
makeBranch("Parameter uX",unite);
translateA = makeBranch("translateA",unite);
makeBranch("Parameter taX",translateA);
translateB = makeBranch("translateB",unite);
makeBranch("Parameter tbX",translateB);
rotate = makeBranch("rotate",translateB);
makeBranch("Parameter RX",rotate);
tree= new TreeView<>(rootnode);
tree.setEditable(true);
tree.setCellFactory(TextFieldTreeCell.forTreeView());
VBox vbox =new VBox(10);
vbox.setPadding(new Insets(5));
Text text= new Text("Fall tree");
text.setFont(Font.font("I", FontWeight.BOLD,16));
vbox.getChildren().addAll(text,tree);
return vbox;
}
private TreeItem<String> makeBranch(String title, TreeItem<String> parent) {
TreeItem<String>item = new TreeItem<>(title);
item.setExpanded(true);
parent.getChildren().add(item);
return item;
}
private Parent getTop() {
TextField fieldName = new TextField();
Button btSave = new Button("Save");
btSave.setOnAction(event -> {
SaveData data = new SaveData();
// data.name = ((TreeView<String>) tree).getText();
data.name = fieldName.getText();
try {
Function.save(data, "Javafx.save");
}
catch (Exception e) {
e.printStackTrace();
}
});
Button btLoad = new Button("Load");
btLoad.setOnAction(event -> {
try {
SaveData data = (SaveData) Function.load("Javafx.save");
//((TreeItems<String>)tree).setText(data.name);
fieldName.setText(data.name);
}
catch (Exception e) {
e.printStackTrace();
}
});
HBox hb= new HBox(5,fieldName,btSave,btLoad);
hb.setPadding(new Insets(5));
return hb;
}
public static void main(String[] args)
{
Application.launch(args);
}
}
And Function class is
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Function {
public static void save(Serializable data, String fileName) throws Exception {
try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get(fileName)))) {
oos.writeObject(data);
}
}
public static Object load(String fileName) throws Exception {
try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get(fileName)))) {
return ois.readObject();
}
}
}
And SaveData Class is
import javafx.scene.control.TreeView;
public class SaveData implements java.io.Serializable{
private static final long serialVersionUID = 1L;
public String name;
}
I wanted to edit the Tree and make changes, save that changes and after next execution, i should have that changed result. Since i don't know much about database so i came up with this method to save changes in a file and load that file.
Problem is that i can save and load text in textfield but i cannot save and load changes in tree.
I want to save changes in tree and load these changes on my next execution. I tried but failed.
Thank you.

Related

Create Nodes within Loop

Note: this is an updatet version of the initial question.
Whats now beeing asked is how I can get access to the values of a certain row for calculations purposes. For example how can I calculate the difference betweeen values of the expensesColumn and the earningsColumn? (Because there was to much code within my questions, I deleted most of the imports)
package application;
import javafx.application.Application;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {Table.create(primaryStage);}
catch(Exception e) {e.printStackTrace();}
}
public static void main(String[] args) {
launch(args);
}
}
package application;
public class UserJava {
private String member;
private double expenses;
private double earnings;
//Getter und Setter
public String getMember() {
return member;
}
public void setMember(String member) {
this.member = member;
}
public double getExpenses() {
return expenses;
}
public void setExpenses(double expenses) {
this.expenses = expenses;
}
public double getEarnings() {
return earnings;
}
public void setEarnings(double earnings) {
this.earnings = earnings;
}
}
package application;
import javafx.stage.Stage;
public class Table {
static TableView<UserJava> table;
public static void create (Stage primaryStage){
try {
GridPane primarygridpane = new GridPane();
HBox hboxTable = new HBox(10);
//Definition der Tabelle
TableColumn<UserJava, String> userColumn = new TableColumn<>("Name");
userColumn.setCellValueFactory(new PropertyValueFactory<>("member"));
userColumn.setMinWidth(200);
TableColumn<UserJava, Double> expensesColumn = new TableColumn<>("Ausgaben");
expensesColumn.setCellValueFactory(new PropertyValueFactory<>("expenses"));
expensesColumn.setMinWidth(100);
TableColumn<UserJava, Double> earningsColumn = new TableColumn<>("Pfand");
earningsColumn.setCellValueFactory(new PropertyValueFactory<>("earnings"));
earningsColumn.setMinWidth(100);
table = new TableView<>();
table.getColumns().addAll(userColumn, expensesColumn, earningsColumn);
TextField tfMember = new TextField();
tfMember.setMinWidth(200);
tfMember.setPromptText("Name");
TextField tfExpenses = new TextField();
tfExpenses.setMinWidth(100);
tfExpenses.setPromptText("Ausgaben");
TextField tfEarnings = new TextField();
tfEarnings.setMinWidth(100);
tfEarnings.setPromptText("Pfand");
Button btnAdd = new Button("Hinzufügen");
Button btnDelete = new Button("Löschen");
hboxTable.getChildren().addAll(tfMember, tfExpenses, tfEarnings, btnAdd, btnDelete);
table.setEditable(true);
userColumn.setCellFactory(TextFieldTableCell.forTableColumn());
// table.setItems(getUser());
//Sonstiges
Scene scene = new Scene(primarygridpane,725,400);
Text titel = new Text("Application");
titel.setFont(Font.font("Arial", FontWeight.BOLD, 28));
primarygridpane.add(titel, 0, 0, 2, 1);
primarygridpane.add(table, 0, 2);
primarygridpane.add(hboxTable, 0, 3);
// scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
//Funktionen
btnAdd.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent e) {
try {
UserJava user = new UserJava();
user.setMember(tfMember.getText());
user.setExpenses(Double.parseDouble(tfExpenses.getText()));
user.setEarnings(Double.parseDouble(tfEarnings.getText()));
table.getItems().add(user);
tfMember.clear();
tfExpenses.clear();
tfEarnings.clear();
System.out.println(table.getItems());
}
catch (NumberFormatException Ausnahme) {}
}
});
btnDelete.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent e) {
try {
ObservableList<UserJava> userSelected, userAll;
userAll = table.getItems();
userSelected = table.getSelectionModel().getSelectedItems();
userSelected.forEach(userAll::remove);
System.out.println();
}
catch (java.util.NoSuchElementException Ausnahme) {}
}
});
}
catch (Exception e) {e.printStackTrace();}
}
public ObservableList<UserJava> getUser(){
ObservableList<UserJava> user = FXCollections.observableArrayList();
user.add(new UserJava());
return user;
}
public void changeCell(CellEditEvent<?, ?> ediditedCell) {
UserJava personSelected = table.getSelectionModel().getSelectedItem();
personSelected.setMember(ediditedCell.getNewValue().toString());
}
}

JavaFX - How to switch to another tab with mouse click event [duplicate]

So I'm trying to load and save Images into an imageView where the location of the image is chosen through a file browser. I've been working on this for several days now and I'm gonna have a stroke if I can't get it fixed. I've tried everything I can think of. Thank you in advance for helping.
UPDATED:
Here is my main class:
public class Main extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
public Main(){}
#Override
public void start(Stage primaryStage) throws Exception{
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Help Please");
initRootLayout();
showScreen();
}
public void initRootLayout(){
try{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
RootLayout controller = loader.getController();
controller.setMain(this);
primaryStage.show();
}catch(Exception e ){e.printStackTrace();}
}
public void showScreen(){
try{FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/sample.fxml"));
BorderPane sample = (BorderPane)loader.load();
rootLayout.setCenter(sample);
Controller controller = loader.getController();
controller.setMain(this);
}catch (Exception e){e.printStackTrace();}
}
public Stage getPrimaryStage(){return primaryStage;}
public static void main(String[] args) {
launch(args);
}
}
Here is the rootLayout:
public class RootLayout {
private Main main;
private Controller controller = new Controller();
public void setMain(Main main){this.main = main;}
#FXML
private void handleOpen(){
FileChooser fileChooser = new FileChooser();
FileChooser.ExtensionFilter extensionFilter = new FileChooser.ExtensionFilter(
"PNG files (*.png)","*png");
fileChooser.getExtensionFilters().add(extensionFilter);
File file = fileChooser.showOpenDialog(main.getPrimaryStage());
if(file!= null){
controller.updateImage(file.toURI().toString());
}
}
}
And here is the controller:
public class Controller implements Initializable {
#FXML
ImageView imageView = new ImageView();
String imageURL;
Main main = new Main();
public void setMain(Main main){
this.main = main;
}
public void updateImage(String url){
if(url.length()>=1){
Image image = new Image(url);
imageView.setImage(image);
System.out.println(url);
}
else{
System.out.println(url);
System.out.println("image invalid");
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
}
Two things:
Never assign a field whose value is to be injected by an FXMLLoader (e.g. #FXML fields). Doing so is a waste of resources at best and introduces subtle bugs at worst. For instance, if you were to leave the imageView field uninitialized you'd be getting a NullPointerException which would indicate a problem with your setup. Since you do initialize the field, however, you don't get any errors and there's a false impression of the code working.
In your RootLayout controller class, you have:
private Controller controller = new Controller();
That instance of Controller you just created is not linked to any FXML file. And since you initialize the imageView field (see first point) you end up updating an ImageView which is not being displayed anywhere; this is where not initializing said field would have given a nice indication of there being a problem. The solution is to pass the Controller instance created by the FXMLLoader to the RootLayout instance created by the other FXMLLoader.
Also, in the same class you have:
Main main = new Main();
Which is also unnecessary since the created instance of Main is both not the correct instance and is replaced by the call to #setMain(Main) almost immediately.
Assuming your FXML files (which you did not provide) are correct, the Java classes should look more like:
Main.java
public class Main extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private RootLayout rootLayoutController;
public Main() {}
#Override
public void start(Stage primaryStage) throws Exception {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Help Please");
initRootLayout();
showScreen();
}
public void initRootLayout() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
// store RootLayout instance in field so #showScreen()
// can reference it
rootLayoutController = loader.getController();
rootLayoutController.setMain(this);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public void showScreen() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("view/sample.fxml"));
BorderPane sample = (BorderPane) loader.load();
rootLayout.setCenter(sample);
Controller controller = loader.getController();
controller.setMain(this);
// set Controller instance on RootLayout instance
rootLayoutController.setController(controller);
} catch (Exception e) {
e.printStackTrace();
}
}
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
RootLayout.java
public class RootLayout {
private Main main;
private Controller controller;
public void setMain(Main main) {
this.main = main;
}
public void setController(Controller controller) {
this.controller = controller;
}
#FXML
private void handleOpen() {
FileChooser fileChooser = new FileChooser();
// Note extensions should be prefixed with "*."
FileChooser.ExtensionFilter extensionFilter =
new FileChooser.ExtensionFilter("PNG files (*.png)", "*.png");
fileChooser.getExtensionFilters().add(extensionFilter);
File file = fileChooser.showOpenDialog(main.getPrimaryStage());
if (file != null) {
controller.updateImage(file.toURI().toString());
}
}
}
Controller.java
public class Controller implements Initializable {
#FXML ImageView imageView; // leave uninitialized, will be injected
String imageURL;
Main main;
public void setMain(Main main) {
this.main = main;
}
public void updateImage(String url) {
if (url.length() >= 1) {
Image image = new Image(url);
imageView.setImage(image);
System.out.println(url);
} else {
System.out.println(url);
System.out.println("image invalid");
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {}
}
Note: Did not test new code.

How to return value from a stage before closing it?

I have a "main stage" where I press a button to open a "second stage" where I have a table, the user selects one item of the the table and click on "asignar" button (which is just a confirm button), once clicked, it must return the code of the item selected in the table to the main stage and close the second stage.
Here is the code that matters.
I have an INT variable which must take the value of a function:
codigo = controller.setVista(this, usuario, password);
The "setVista" function goes like this:
public int setVista(ListHorarios vista, String usuario, String password) {
this.vista = vista;
this.usuario = usuario;
this.password = password;
this.inicializarTabla();
this.actualizarTabla(0, "%");
btnSeleccionar.setOnAction(e -> {
asignarSeleccion();
Stage stage = (Stage) btnSeleccionar.getScene().getWindow();
stage.close();
});
return codigo_horario;
}
And the "asignarSeleccion" like this:
private void asignarSeleccion() {
final HorarioTableModelo aux_horario = getTablaSeleccionada();
posicion = datos.indexOf(aux_horario);
if (aux_horario != null) {
codigo_horario = aux_horario.getCodigo();
}
}
My problem is that I can't get the "codigo_horario" value into the first variable "codigo" before the stage closes, what do I am missing?
Here is a possible example. The structure is the same as in the answer in my comment.
The second Stage is opened through a "controller" that is stores the data that should be returned even when the Stage is closed and exposes a getter to be used to retrieve the value from the outer world.
import javafx.application.Application;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
Button bSecondStage = new Button("Show second Stage");
bSecondStage.setOnAction(e -> {
WindowController wc = new WindowController();
wc.showStage();
System.out.println(wc.getData());
});
root.setCenter(bSecondStage);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
class WindowController {
private String data;
void showStage() {
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
VBox root = new VBox();
Scene scene = new Scene(root);
TextField tf = new TextField();
Button submit = new Button("Submit");
submit.setOnAction(e -> {
data = tf.getText();
stage.close();
});
root.getChildren().addAll(tf, submit);
stage.setScene(scene);
stage.showAndWait();
}
String getData() {
return data;
}
}
}
You can write your own Stage class with a return statement.
public class MyStage extends Stage {
public String showAndReturn(myFXControll controll) {
super.showAndWait();
return controll.getReturn();
}
}
After that you have to define a return function to your controller.
public class TableFilterControll implements Initializable {
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
}
public String getReturn() {
return "I'm a nice return value"; //return what you want controlled by your controller class
}
}
Now you can controll your return from the parent controller.
String retValue=myStage.showAndReturn(childControll);
System.out.println(retValue);
I think this is a good solution for clean code. And you can style your FXML with Screne Builder.
There is some error in 4baad4's example. If the method in the controller is iCanGetDataBeforeClose, then that's what should be called:
String someValue = controller.iCanGetDataBeforeClose();
But even that didn't work right for me. I actually got this to work without using setOnCloseRequest at all. In the form controller, I had a method like this:
public boolean getCompleted() {
return this.finished;
}
Then in the form calling it:
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("myView.fxml"));
AnchorPane pane = (AnchorPane) loader.load();
myViewController controller = loader.getController();
Scene scene = new Scene(pane);
Stage stage = new Stage();
stage.setScene(scene);
stage.showAndWait();
if (controller.getCompleted()){
doStuff();
}
One might think that since the stage had exited that the controller would throw a null reference exception, but it didn't, and it returned the correct response.
This solution works and is simplest proposed IMHO.
In my main controller I create Stage. Load controller which I can use like any class. And by creating an event I can get data just before closing the window.
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/package/mySceneBuilderWindow.fxml"));
final Pane rootPane = (Pane)loader.load();
Scene scene = new Scene(rootPane);
Stage stage = new Stage();
stage.setTitle("Optional title");
stage.setScene(scene);
mySceneBuilderWindowController controller = loader.<mySceneBuilderWindowController>getController();
controller.iCanSendDataToCtrl("String for now"); // sending data or init textFields...
stage.show();
/* set event which is fired on close
// How to close in the other window... (pressing X is OK too)
#FXML private Button fxidSave = new Button(); // global var
#FXML private void handleSaveButton() {
Stage stage = (Stage) fxidSave.getScene().getWindow();
stage.close(); // closes window
}
*/
stage.setOnCloseRequest((EventHandler<WindowEvent>) new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
String iCanGetDataBeforeClose = controller.getData();
System.out.println(iCanGetDataBeforeClose);
// static class can be used aswell -> System.out.println(Context.getMyString());
}
});
} catch (IOException e) {
System.out.println("something wrong with .fxml - name wrong? path wrong? building error?");
}
My other mySceneBuilderWindowController methods:
public void iCanSendDataToCtrl(String giveMe) {
// do something ex. myTextBox.setText(giveMe);
}
public String iCanGetDataBeforeClose() {
// do something ex. return myTextBox.getText();
}

How to access table data from outside the controller in javafx

I'm trying to create a material inventory program that uses a tableview. I have a controller that will show statistics based on that tableview but I'm not sure how to access the live data from that view.
My MainApp loads the last saved table and my MaterialOverviewController has the tableview.
I have a RootLayoutController which is my main layout controller which has a simple file menu but also is where the OnFloorStatsController is loaded from.
I can obviously create a new MainApp when the OnFloorStatsController is loaded but this only loads the sample data that was entered by default.
How do I access the live data from the MainApp?
Here is my MainApp code:
public class MainApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private ObservableList<Material> materialData = FXCollections.observableArrayList();
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Label Inventory");
this.primaryStage.getIcons().add(new Image("file:resources/images/1462487405_Mask.png"));
initRootLayout();
showMaterialOverview();
}
public MainApp() {
// Add some sample data
}
public ObservableList<Material> getMaterialData() {
return materialData;
}
/**
* Initializes the root layout and tries to load the last opened
* material file.
*/
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class
.getResource("RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
// Give the controller access to the main app.
RootLayoutController controller = loader.getController();
controller.setMainApp(this);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
// Try to load last opened person file.
File file = getMaterialFilePath();
if (file != null) {
loadMaterialDataFromFile(file);
}
}
public void showMaterialOverview() {
try {
// Load material overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("MaterialOverview.fxml"));
AnchorPane materialOverview = (AnchorPane) loader.load();
// Set material overview into the center of root layout.
rootLayout.setCenter(materialOverview);
// Give the controller access to the main app.
MaterialOverviewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
public void showOnFloorStatistics() {
try {
// Load the fxml file and create a new stage for the popup.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("OnFloorStats.fxml"));
AnchorPane page = (AnchorPane) loader.load();
Stage dialogStage = new Stage();
dialogStage.setTitle("Material On Floor");
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.initOwner(primaryStage);
Scene scene = new Scene(page);
dialogStage.setScene(scene);
// Set the material into the controller.
OnFloorStatsController controller = loader.getController();
controller.start(dialogStage);
dialogStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void showBarChartTest() {
try {
// Load the fxml file and create a new stage for the popup.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("BarChartTestLayout.fxml"));
AnchorPane page = (AnchorPane) loader.load();
Stage dialogStage = new Stage();
dialogStage.setTitle("Detailed Bar Chart");
//
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.initOwner(primaryStage);
Scene scene = new Scene(page);
dialogStage.setScene(scene);
// Set the material into the controller.
BarChartTest controller = loader.getController();
controller.start(dialogStage);
dialogStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the main stage.
* #return
*/
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
}
And here is my MaterialOverViewController code:
public class MaterialOverviewController {
#FXML
private TableView<Material> materialTable;
private List<Material> materialId;
public TableView<Material> getMaterialTable() {
return materialTable;
}
// public void setMaterialTable(TableView<Material> materialTable) {
// this.materialTable = materialTable;
}
private ObservableList<Integer> rollsTotal = FXCollections.observableArrayList();
private ObservableList<String> materialNames = FXCollections.observableArrayList();
// Reference to the main application.
private MainApp mainApp;
/**
* The constructor.
* The constructor is called before the initialize() method.
*/
public MaterialOverviewController() {
}
/**
* Initializes the controller class. This method is automatically called
* after the fxml file has been loaded.
*/
#FXML
private void initialize() {
materialTotal = 0;
// Initialize the material table with columns.
pONumberColumn.setCellValueFactory(cellData -> cellData.getValue().pONumberProperty());
materialNameColumn.setCellValueFactory(cellData -> cellData.getValue().materialNameProperty());
materialIdColumn.setCellValueFactory(cellData -> cellData.getValue().materialIdProperty());
materialWidthColumn.setCellValueFactory(cellData -> cellData.getValue().materialWidthProperty().asObject());
qtyOrderedColumn.setCellValueFactory(cellData -> cellData.getValue().qtyOrderedProperty().asObject());
qtyReceivedColumn.setCellValueFactory(cellData -> cellData.getValue().qtyReceivedProperty().asObject());
qtyBackOrderedColumn.setCellValueFactory(cellData -> cellData.getValue().qtyBackOrderedProperty().asObject());
// qtyBackOrderedColumn.setCellValueFactory(cellData -> cellData.getValue().qtyBackOrderedProperty().asObject());
qtyOnFloorColumn.setCellValueFactory(cellData -> cellData.getValue().qtyOnFloorProperty().asObject());
// dateOrderedColumn.setCellValueFactory(cellData -> cellData.getValue().dateOrderedProperty().asString());
dateOrderedColumn.setCellValueFactory(cellData -> cellData.getValue().dateOrderedProperty().asString());
estArrivalColumn.setCellValueFactory(cellData -> cellData.getValue().dateExpectedProperty().asString());
supplierColumn.setCellValueFactory(cellData -> cellData.getValue().supplierProperty());
// Clear material details.
showMaterialDetails(null);
// Listen for selection changes and show the material details when changed.
materialTable.getSelectionModel().selectedItemProperty().addListener(
(observable, oldValue, newValue) -> showMaterialDetails(newValue));
}
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
// Add observable list data to the table
materialTable.setItems(mainApp.getMaterialData());
}
private void showMaterialDetails(Material material) {
if (material != null) {
// Fill the labels with info from the material object.
pONumberLabel.setText(material.getPoNumber());
materialIdLabel.setText(material.getMaterialId());
materialNameLabel.setText(material.getMaterialName());
materialWidthLabel.setText(String.valueOf(material.getMaterialWidth()));
qtyOrderedLabel.setText(Integer.toString(material.getQtyOrdered()));
qtyRecievedLabel.setText(Integer.toString(material.getQtyReceived()));
qtyBackOrderedLabel.setText(Integer.toString(material.getQtyOrdered()-material.getQtyReceived()));
// qtyBackOrderedLabel.setText(Integer.toString(material.getQtyBackOrdered()));
qtyOnFloorLabel.setText(Integer.toString(material.getQtyOnFloor()));
// dateOrderedLabel.setText(DateUtil.format(material.getDateOrdered()));
// dateOrderedLabel.equals(DateUtil.format(material.getDateOrdered()));
// dateOrderedLabel.setText(DatePicker(String.valueOf(material.getDateOrdered());
// estArrivalLabel.setText(material.getSupplier());
supplierLabel.setText(material.getSupplier());
String pattern = "MM/dd/yyyy";
// dateTestTextField.setText(DateUtil.format(material.getBirthday()));
dateOrderedLabel.setText(DateUtil.format(material.getDateOrdered()));
estArrivalLabel.setText(DateUtil.format(material.getDateExpected()));
//TODO: set running material totals
// getMaterialNames(Arrays.asList(material));
handleSelectMaterial();
}
}
}
public List getMaterialNames(List<Material> materials) {
for (Material name : materials) {
mainApp.getMaterialData();
if (!materialNames.contains(name)) {
materialNames.add(name.getMaterialName());
}
}
for (String name : materialNames) {
materialTextField.setText(name + "\n");
}
return Arrays.asList(materialNames);
}
}
}
Here is the bit of code that works from my RootLayoutController but I'm not sure why I can't do the same thing from the OnFloorStatsController:
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
#FXML
private void handlePrint() {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("MaterialOverview.fxml"));
try {
AnchorPane frame = fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
MaterialOverviewController c = fxmlLoader.getController();
//Loads data into table
c.setMainApp(mainApp);
I just need access to the live data from the MaterialOvewViewController
Here's the OnFloorStatsController:
private MainApp mainApp;
public TableView<Material> material;
/**
* Is called by the main application to give a reference back to itself.
*
* #param mainApp
*/
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
}
// final static String austria = "14532";
// final static String brazil = "78333";
// final static String france = "40443";
// final static String italy = "72825";
// final static String usa = "72829";
public void start(Stage stage) {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("MaterialOverview.fxml"));
try {
AnchorPane frame = fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
MaterialOverviewController c = fxmlLoader.getController();
//Loads data into table
c.setMainApp(mainApp);
stage.setTitle("Material On Floor");
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis();
final BarChart<String, Number> bc =
new BarChart<String, Number>(xAxis, yAxis);
bc.setTitle("Material On Floor");
xAxis.setLabel("Material");
yAxis.setLabel("Quantity");
XYChart.Series series1 = new XYChart.Series();
series1.setName("6 inch");
Integer floorTotal = 0;
for (Material id :mainApp.getMaterialData()) {
if (id.getMaterialWidth() < 6.9) {
floorTotal = id.getQtyOnFloor();
for (Material size : mainApp.getMaterialData()) {
if ( id.getMaterialId().equalsIgnoreCase(size.getMaterialId()) &&
size.getMaterialWidth() == id.getMaterialWidth()) {
floorTotal += size.getQtyOnFloor();
}
else {
floorTotal = id.getQtyOnFloor();
}

JavaFX MultiThreading Flashing Lights

I have two circles redCircle and greenCircle : -
Circle greenCircle = new Circle(250,150 ,100, Color.TRANSPARENT);
Circle redCircle = new Circle(250,450,100,Color.TRANSPARENT);
greenCircle.setStroke(Color.GREEN);
greenCircle.setStrokeWidth(4);
group.getChildren().add(greenCircle);
redCircle.setStroke(Color.RED);
redCircle.setStrokeWidth(4);
group.getChildren().add(redCircle);
Basically I want Circle to turn on and off twice in 2 seconds. So I am able to turn on Light then wait for 0.5 second , turn off and again wait for 0.5 second and turn on Light. I am not about to turn off after 0.5 second.
public class LightOn {
public Task<Void> runLightOn() throws InterruptedException {
return new Task<Void>(){
#Override
protected Void call() throws Exception {
greenCircle.setFill(Color.GREEN);
return null;
}
};
}
}
public class LightOff {
public void perform() throws InterruptedException {
LightOn onL = new LightOn();
Task<Void> runLinghtOnTask = onL.runLightOn();
runLinghtOnTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(MovementEventsDemo.class.getName()).log(Level.SEVERE, null, ex);
}
greenCircle.setFill(Color.TRANSPARENT);
nextFunction();
}
});
new Thread(runLinghtOnTask).start();
}
}
public void nextFunction(){
Task<Void> sleeper2 = new Task<Void>() {
#Override
protected Void call() throws Exception {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
return null;
}
};
sleeper2.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
if(greenCircle.getFill()==Color.GREEN) {
greenCircle.setFill(Color.TRANSPARENT);
}else {
greenCircle.setFill(Color.GREEN);
}
}
});
new Thread(sleeper2).start();
}
I use this to execute : -
LightOff lf = new LightOff();
lf.perform();
The reason your code is not working is that an exception is being thrown in the call() method of the Task returned by runLightOn(), because you are changing the UI from a background thread. If you catch the exception or register an onFailed handler with the Tasks you will be able to log the exception.
For functionality like this, where you have specific timepoints (KeyFrames) at which you want values to change, use a Timeline instead of messing with multithreading:
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class FlashingLight extends Application {
#Override
public void start(Stage primaryStage) {
Circle circle = new Circle(250, 150, 100, Color.TRANSPARENT);
circle.setStroke(Color.GREEN);
circle.setStrokeWidth(4);
Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(0.5), e -> circle.setFill(Color.GREEN)),
new KeyFrame(Duration.seconds(1.0), e -> circle.setFill(Color.TRANSPARENT))
);
timeline.setCycleCount(2);
Pane pane = new Pane(circle);
Scene scene = new Scene(pane, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
timeline.play();
}
public static void main(String[] args) {
launch(args);
}
}
As a slight alternative, you can replace
Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(0.5), e -> circle.setFill(Color.GREEN)),
new KeyFrame(Duration.seconds(1.0), e -> circle.setFill(Color.TRANSPARENT))
);
with
BooleanProperty on = new SimpleBooleanProperty();
Timeline timeline = new Timeline(
new KeyFrame(Duration.seconds(0.5), new KeyValue(on, true)),
new KeyFrame(Duration.seconds(1.0), new KeyValue(on, false))
);
circle.fillProperty().bind(
Bindings.when(on)
.then(Color.GREEN)
.otherwise(Color.TRANSPARENT));
The added benefits here are that you create a boolean value representing whether or not the light is on, which may be useful elsewhere in your logic, and that you separate the logic (on/off, and the timing) from the display (color, etc).

Resources