Accessing buttons in TableView - java

Using Scenebuilder I created a TableView and I insert several items in to it from a local Database. The items are type of a Class Symptom I've created.
package javafxapplication4;
import javafx.scene.control.Button;
public class Symptom {
private String name,category,symptomId;
private Button symptom;
public Symptom(String name,String category,String symptomId){
this.name = name;
this.category = category;
this.symptomId = symptomId;
this.symptom = new Button("Select Symptom");
//setGraphic(add_symptom);
}
public String getName(){
return this.name;
}
public String getCategory(){
return this.category;
}
public void setName(String name){
this.name = name;
}
public void setCategory(String category){
this.category = category;
}
public void setSymptom(Button button){
symptom = button;
}
public Button getSymptom(){
return symptom;
}
public void setSymptomId(String symptomId){
this.symptomId = symptomId;
}
public String getSymptomId(){
return this.symptomId;
}
}
I've given 3 columns to the TableView. Name,Category and an action column where the symptom button appears to perform a certain action.
TableView
This is my FXML Controller.
package javafxapplication4;
import java.net.URL;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import java.util.ResourceBundle;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
public class Symptom_DataController implements Initializable {
/**
* Initializes the controller class.
*/
#FXML
private TableView<Symptom> symptomsTable;
#FXML
private TableColumn<Symptom,String> nameColumn;
#FXML
private TableColumn<Symptom,String> categoryColumn;
#FXML
private TableColumn<Symptom,String> actionColumn;
#FXML
private Button cancel;
#FXML
private Button diagnose;
public LoginModel loginModelSymptomsTable = new LoginModel();
#FXML
private void cancelAction(ActionEvent e) throws Exception{
Stage stage;
Scene scene;
Parent root;
if ( e.getSource() == cancel ) {
stage = (Stage) cancel.getScene().getWindow();
root = FXMLLoader.load(getClass().getResource("Menu.fxml"));
scene = new Scene(root);
stage.setX(0);
stage.setY(0);
stage.setMinWidth(800);
stage.setMinHeight(600);
stage.setWidth(1024);
stage.setHeight(768);
stage.setScene(scene);
stage.show();
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
nameColumn.setCellValueFactory(new PropertyValueFactory<>("Name"));
categoryColumn.setCellValueFactory(new PropertyValueFactory<>("Category"));
actionColumn.setCellValueFactory(new PropertyValueFactory<Symptom,String>("symptom"));
symptomsTable.setItems(loginModelSymptomsTable.selectSymptomValue());
}
}
Using an ObservableList I fill the TableView. Now i want to create an action for every button according to the row it's placed in the TableView. I can perform an action to the Button as long as I've selected a row in the TableView (cause that gives me access to the Symptom object). How can I perform an action with the button just by clicking on it and without selecting a row?
P.S: Sorry for my bad English. If this is a duplicate post, please direct me to the right way of doing this.

The button should not be part of the model class Symptom: instead you should create a TableCell that displays the button.
So the table setup should be something like:
#FXML
private TableView<Symptom> symptomsTable;
#FXML
private TableColumn<Symptom,String> nameColumn;
#FXML
private TableColumn<Symptom,String> categoryColumn;
// value for the action column is just going to be the entire symptom,
// so the type of the column is TableColumn<Symptom, Symptom>
#FXML
private TableColumn<Symptom,Symptom> actionColumn;
#Override
public void initialize(URL url, ResourceBundle rb) {
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
categoryColumn.setCellValueFactory(new PropertyValueFactory<>("category"));
// just provide the entire row as the value for cells in the actionColumn:
actionColumn.setCellValueFactory(cellData -> new SimpleObjectProperty<>(cellData.getValue()));
// cell factory which provides cell which display a button:
actionColumn.setCellFactory(column -> new TableCell<Symptom, Symptom>() {
private final Button button = new Button("Select Symptom");
{
button.setOnAction(e -> {
Symptom symptom = getItem();
// do whatever you need with symptom..
});
}
#Override
protected void updateItem(Symptom item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
setGraphic(button);
}
}
});
symptomsTable.setItems(loginModelSymptomsTable.selectSymptomValue());
}
And then just remove the button entirely from the Symptom class.

Related

JavaFX TableView with CheckBoxes: retrieve the rows whose checkboxes are checked

I've been searching for a while, but all I found seems very old and can't get it to work and I'm very confused.
I have a tableview with a checkbox in a column header (select all) and another checkbox for each row (select row). What I am trying to achieve is to get all the rows whose checkboxes are checked to perform an action.
Here's what it looks like:
And here's the code in my controller:
package com.comparador.controller;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.comparador.ComparadorPreciosApplication;
import com.comparador.entity.Commerce;
import com.comparador.entity.Items;
import com.comparador.entity.ShoppingListPrices;
import com.comparador.repository.CommerceRepository;
import com.comparador.repository.ProductRepository;
import com.comparador.service.ShoppingService;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.stage.Stage;
import javafx.util.converter.IntegerStringConverter;
#Component
public class ShoppingController implements Initializable {
// #Autowired
// #Qualifier("lblTitulo")
private String titulo = "Productos";
#Autowired
private ProductRepository productRepository;
#Autowired
private CommerceRepository commerceRepository;
#Autowired
private ShoppingService shoppingService;
#FXML
private Label lblTitulo;
#FXML
private Button btBack;
#FXML
private TableView<Items> tvProducts;
#FXML
private TableColumn<Items, CheckBox> colSelected; //THE CHECKBOX COLUMN
#FXML
private TableColumn<Items, String> colName;
#FXML
private TableColumn<Items, Integer> colAmount;
#FXML
private TableView<ShoppingListPrices> tvTotalPrices;
#FXML
private TableColumn<ShoppingListPrices, String> colCommerce;
#FXML
private TableColumn<ShoppingListPrices, Double> colTotal;
private CheckBox selectAll;
List<ShoppingListPrices> shoppingList = new ArrayList<>();
#Override
public void initialize(URL location, ResourceBundle resources) {
colName.setCellValueFactory(new PropertyValueFactory<>("name"));
colAmount.setCellValueFactory(new PropertyValueFactory<>("amount"));
colAmount.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
// colSelected.setCellFactory(CheckBoxTableCell.forTableColumn(colSelected));
// colSelected.setCellValueFactory(cellData -> new ReadOnlyBooleanWrapper(cellData.getValue().getChecked()));
colSelected.setCellValueFactory(new PropertyValueFactory<>("selected"));
colCommerce.setCellValueFactory(new PropertyValueFactory<>("commerceName"));
colTotal.setCellValueFactory(new PropertyValueFactory<>("total"));
lblTitulo.setText(titulo);
tvProducts.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
reloadTableViewProducts();
selectAll = new CheckBox();
selectAll.setOnAction(event -> {
event.consume();
tvProducts.getItems().forEach(item -> {
item.getSelected().setSelected(selectAll.isSelected());
});
});
setShoppingList();
colSelected.setGraphic(selectAll);
}
#FXML
public void editAmount(CellEditEvent<Items, Integer> event) {
Items item = event.getRowValue();
if(event.getTableColumn().getText().equals("Cantidad")) {
item.setAmount(event.getNewValue());
}
setShoppingList();
}
/*
* CLICKING ON A CHECKBOX SHOULD CALL THIS METHOD AND ADD THE ROW TO "selectedItems"
*/
#FXML
public void setShoppingList() {
List<Items> selectedItems = new ArrayList<>();
//Before trying this I was selecting each row by Ctrl + Clicking on it
// List<Items> selectedItems = tvProducts.getSelectionModel().getSelectedItems();
//This didn't seem to work
// List<ShoppingListItems> selectedItems = tvProducts.getItems().filtered(x->x.getSelected() == true);
List<Commerce> commerces = commerceRepository.findByNameContaining("");
ShoppingListPrices pricesMixingCommerces = shoppingService.getCheapestShoppingList(commerces, selectedItems);
List<ShoppingListPrices> pricesByCommerce = shoppingService.getShoppingListsPerCommerce(commerces, selectedItems);
shoppingList = new ArrayList<>();
shoppingList.add(pricesMixingCommerces);
shoppingList.addAll(pricesByCommerce);
ObservableList<ShoppingListPrices> resultOL = FXCollections.observableArrayList();
resultOL.addAll(shoppingList);
tvTotalPrices.setItems(resultOL);
}
#FXML
public void openShoppingList() throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/shoppingList.fxml"));
ShoppingListController shoppingListController = new ShoppingListController();
loader.setControllerFactory(ComparadorPreciosApplication.applicationContext::getBean);
loader.setController(shoppingListController);
shoppingListController.setup(tvTotalPrices.getSelectionModel().getSelectedItem());
try {
Scene scene = new Scene(loader.load(), 800, 400, true, SceneAntialiasing.BALANCED);
Stage stage = new Stage();//(Stage) btBack.getScene().getWindow();
stage.setUserData(tvTotalPrices.getSelectionModel().getSelectedItem());
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
#FXML
public void goBack() {
FXMLLoader loader = new FXMLLoader(ComparadorPreciosApplication.class.getResource("/index.fxml"));
loader.setControllerFactory(ComparadorPreciosApplication.applicationContext::getBean);
try {
Scene scene = new Scene(loader.load(), 800, 800, false, SceneAntialiasing.BALANCED);
Stage stage = (Stage) btBack.getScene().getWindow();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void reloadTableViewProducts() {
List<String> productNames = productRepository.findOnProductPerName("");
List<Items> items = new ArrayList<>();
for(String name : productNames) {
//items.add(new Items(new SimpleBooleanProperty(false), name, 1));
Items item = new Items((CheckBox) new CheckBox(), name, 1);
item.getSelected().setSelected(false);
items.add(item);
}
ObservableList<Items> itemsOL = FXCollections.observableArrayList();
itemsOL.addAll(items);
tvProducts.setItems(itemsOL);
}
}
Your Items class should not reference any UI objects, including CheckBox. The model should ideally not even know the view exists. If you plan on having Items track if it's selected itself, then it should expose a BooleanProperty representing this state. With a properly configured table and column, the check box associated with an item and the item's selected property will remain synchronized. And since the items of the table keep track of their own selected state, getting all the selected items is relatively straightforward. Simply iterate/stream the items and grab all the selected ones.
Here's an example using CheckBoxTableCell:
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
var table = new TableView<Item>();
table.setEditable(true);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
for (int i = 0; i < 50; i++) {
table.getItems().add(new Item("Item #" + (i + 1)));
}
var selectedCol = new TableColumn<Item, Boolean>("Selected");
// configure cell factory to use a cell implementation that displays a CheckBox
selectedCol.setCellFactory(CheckBoxTableCell.forTableColumn(selectedCol));
// link CheckBox and model selected property
selectedCol.setCellValueFactory(data -> data.getValue().selectedProperty());
table.getColumns().add(selectedCol);
var nameCol = new TableColumn<Item, String>("Name");
nameCol.setCellValueFactory(data -> data.getValue().nameProperty());
table.getColumns().add(nameCol);
var button = new Button("Print checked items");
button.setOnAction(e -> {
// filter for selected items and collect into a list
var checkedItems = table.getItems().stream().filter(Item::isSelected).toList();
// log selected items
System.out.printf("There are %,d checked items:%n", checkedItems.size());
for (var item : checkedItems) {
System.out.println(" " + item);
}
});
var root = new BorderPane();
root.setTop(button);
root.setCenter(table);
root.setPadding(new Insets(10));
BorderPane.setMargin(button, new Insets(0, 0, 10, 0));
BorderPane.setAlignment(button, Pos.CENTER_RIGHT);
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}
public static class Item {
private final StringProperty name = new SimpleStringProperty(this, "name");
public final void setName(String name) { this.name.set(name); }
public final String getName() { return name.get(); }
public final StringProperty nameProperty() { return name; }
private final BooleanProperty selected = new SimpleBooleanProperty(this, "selected");
public final void setSelected(boolean selected) { this.selected.set(selected); }
public final boolean isSelected() { return selected.get(); }
public final BooleanProperty selectedProperty() { return selected; }
public Item() {}
public Item(String name) {
setName(name);
}
#Override
public String toString() {
return String.format("Item(name=%s, selected=%s)", getName(), isSelected());
}
}
}
Note that TableView has a selection model. That is not the same thing. It's used for the selection of rows or cells of the table (and thus works best on a per-table basis). You, however, want to be able to "check" items, and that requires keeping track of that state differently--an item's row could be selected while the item is not checked, and vice versa.
And note I recommend that any model class used with TableView expose JavaFX properties (like the Item class in the example above). It makes it much easier to work with TableView. But that could interfere with other parts of your code (e.g., Spring). In that case, you could do one of three things:
Create a simple adapter class that holds a reference to the "real" object and provides a BooleanProperty. This adapter class would only be used for the TableView.
Create a more complex adapter class that mirrors the "real" class in content, but exposes the properties as JavaFX properties (e.g., BooleanProperty, StringProperty, etc.). Map between them as you cross layer boundaries in your application.
In the controller, or wherever you have the TableView, keep the selected state external to the model class. For instance, you could use a Map<Item, BooleanProperty>.
I probably would only use this approach as a last resort, if ever.

Changes from JavaFX Controller are not saved in List from other Object

I'm new to Java and JavaFX. As a first project I try to make an adress book but I am getting a problem which I can't resolve.
I have a MainClass which opens a window where the user can select to search a Person or add a Person. I also have a second window which opens when the Person, which the user enters by first- and last name is found and displays the Person's details. This window provides a button which opens another (a third) window where the user can change the details. All the information is stored in a Arzt.java class which contains an ObservableList.
My Problem is that any changes I apply aren't saved in the Arzt.java class ObservableList.
I hope you can help me there. Help is much appreciated!
App.java (MainClass):
package com.mycompany.doktorenkartei;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class App extends Application {
private Scene scene;
private Stage stage;
#Override
public void start(Stage stage) throws IOException {
this.stage = stage;
showStartpage();
}
public void showStartpage() throws IOException {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(App.class.getResource("startpage.fxml"));
scene = new Scene(loader.load());
stage.setScene(scene);
stage.setResizable(false);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
Controller of the first window:
package com.mycompany.doktorenkartei;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class StartpageController {
#FXML
private Button findDocWindow;
#FXML
private Button addDocWindow;
#FXML
private void findDoctorWindow() throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("arztSuchen.fxml"));
Parent root = (Parent) fxmlLoader.load();
Stage stage = new Stage();
stage.setTitle("Suche");
stage.setScene(new Scene(root));
stage.show();
}
#FXML
private void addDoctorWindow() {
System.out.println("Button works also");
}
}
Controller of the searchwindow:
package com.mycompany.doktorenkartei;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class ArztSuchenController implements Initializable {
private Kartei kartei;
#FXML
private TextField fieldNachname;
#FXML
private TextField fieldVorname;
#FXML
private Button searchButton;
#Override
public void initialize(URL location, ResourceBundle resources){
kartei = new Kartei();
}
public void setKartei(Kartei kartei){
this.kartei = kartei;
}
public ArztSuchenController(){
}
#FXML
void searchForDoctor(ActionEvent event) throws IOException {
String vorname = fieldVorname.getText();
String name = fieldNachname.getText();
if (this.kartei.arztExsist(vorname, name)) {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("arztFenster.fxml"));
Parent root1 = loader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root1));
ArztFensterController controller = loader.getController();
controller.showInformations(this.kartei.getArzt(vorname, name));
//closing stage if Arzt found
Stage stageSuchen = (Stage) searchButton.getScene().getWindow();
stageSuchen.close();
stage.show();
} else {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("nichtGefundenFenster.fxml"));
Parent root1 = loader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root1));
stage.show();
}
}
}
Controller of the Window where details are changed:
package com.mycompany.doktorenkartei;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
public class ArztBearbeitenController {
private Arzt ausgewählterArzt;
#FXML
private Button speichern;
#FXML
private TextArea textAnmerkung;
#FXML
private TextField textApprobation;
#FXML
private TextField textArbeitsbegin;
#FXML
private TextField textBerufstätig;
#FXML
private TextField textBundesland;
#FXML
private TextField textErhaltRate;
#FXML
private TextField textFacharzt;
#FXML
private TextField textFamilienstand;
#FXML
private TextField textGeburtstag;
#FXML
private TextField textHeimatadresse;
#FXML
private TextField textImpfstatus;
#FXML
private TextField textNachname;
#FXML
private TextField textName;
#FXML
private TextField textNationalität;
#FXML
private TextField textSprachkurs;
#FXML
private TextField textSprachniveau;
#FXML
private TextField textStudium;
#FXML
private TextField textUnterkunft;
#FXML
private TextField textVisum;
public ArztBearbeitenController() {
}
#FXML
void saveTextfield(ActionEvent event) {
this.ausgewählterArzt.setVorname(textName.getText());
this.ausgewählterArzt.setNachname(textNachname.getText());
this.ausgewählterArzt.setGeburtsdatum(textGeburtstag.getText());
this.ausgewählterArzt.setNationalität(textNationalität.getText());
this.ausgewählterArzt.setFamilienstand(textFamilienstand.getText());
this.ausgewählterArzt.setHeimatadresse(textHeimatadresse.getText());
this.ausgewählterArzt.setAdresseUnterkunft(textUnterkunft.getText());
this.ausgewählterArzt.setVisum(textVisum.getText());
this.ausgewählterArzt.setImpfstatus(textImpfstatus.getText());
this.ausgewählterArzt.setSprachniveau(textSprachniveau.getText());
this.ausgewählterArzt.setBerufstätig(textBerufstätig.getText());
this.ausgewählterArzt.setBundesland(textBundesland.getText());
this.ausgewählterArzt.setSprachkurs(textSprachkurs.getText());
this.ausgewählterArzt.setFacharzt(textFacharzt.getText());
this.ausgewählterArzt.setApprobation(textApprobation.getText());
this.ausgewählterArzt.setStudium(textStudium.getText());
this.ausgewählterArzt.setArbeitsbegin(textArbeitsbegin.getText());
this.ausgewählterArzt.setErhaltRate(textErhaltRate.getText());
this.ausgewählterArzt.setAnmerkungen(textAnmerkung.getText());
}
public void fillTextfields(Arzt arzt) {
this.ausgewählterArzt = arzt;
textName.setText(arzt.getVornameString());
textNachname.setText(arzt.getNachnameString());
textGeburtstag.setText(arzt.getGeburtsdatumString());
textNationalität.setText(arzt.getNationalitätString());
textFamilienstand.setText(arzt.getFamilienstandString());
textHeimatadresse.setText(arzt.getHeimatadresseString());
textUnterkunft.setText(arzt.getAdresseUnterkunftString());
textVisum.setText(arzt.getVisumString());
textImpfstatus.setText(arzt.getImpfstatusString());
textSprachniveau.setText(arzt.getSprachniveauString());
textBerufstätig.setText(arzt.getBerufstätigString());
textBundesland.setText(arzt.getBundeslandString());
textSprachkurs.setText(arzt.getSprachkursString());
textFacharzt.setText(arzt.getFacharztString());
textApprobation.setText(arzt.getApprobationString());
textStudium.setText(arzt.getStudiumString());
textArbeitsbegin.setText(arzt.getArbeitsbeginString());
textErhaltRate.setText(arzt.getErhaltRateString());
textAnmerkung.setText(arzt.getAnmerkungenString());
}
}
The class where the Data should be stored(temporary, in future saved as xml file):
package com.mycompany.doktorenkartei;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
public class Kartei {
private ObservableList<Arzt> kartei = FXCollections.observableArrayList();
#FXML private ArztSuchenController suchenController;
#FXML private ArztFensterController arztController;
public Kartei() {
//data for testing
kartei.add(new Arzt("Nelson", "Mandela"));
kartei.add(new Arzt("Isaac", "Newton"));
kartei.add(new Arzt("Josepe", "Trymeout"));
}
public ObservableList<Arzt> getKartei() {
return this.kartei;
}
#FXML private void initialize(){
suchenController.setKartei(this);
}
public boolean arztExsist(String vorname, String nachname) {
for (Arzt e : this.kartei) {
if (e.getVornameString().equalsIgnoreCase(vorname) && e.getNachnameString().equalsIgnoreCase(nachname)) {
return true;
}
}
return false;
}
public Arzt getArzt(String vorname, String nachname) {
for (Arzt e : this.kartei) {
if (e.getVornameString().equalsIgnoreCase(vorname) && e.getNachnameString().equalsIgnoreCase(nachname)) {
return e;
}
}
return null;
}
}
The Person Class:
package com.mycompany.doktorenkartei;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Arzt {
private StringProperty vorname;
private StringProperty nachname;
private StringProperty geburtsdatum;
private StringProperty nationalität;
private StringProperty familienstand;
private StringProperty heimatadresse;
private StringProperty adresseUnterkunft;
private StringProperty visum;
private StringProperty impfstatus;
private StringProperty Sprachniveau;
private StringProperty berufstätig;
private StringProperty facharzt;
private StringProperty approbation;
private StringProperty studium;
private StringProperty bundesland;
private StringProperty sprachkurs;
private StringProperty arbeitsbegin;
private StringProperty erhaltRate;
private StringProperty anmerkungen;
public Arzt(String vorname, String nachname) {
this.vorname = new SimpleStringProperty(vorname);
this.nachname = new SimpleStringProperty(nachname);
//dummyData
this.geburtsdatum = new SimpleStringProperty("asdasdasd");
this.nationalität = new SimpleStringProperty("asdasdasd");
this.familienstand = new SimpleStringProperty("asdasdasd");
this.heimatadresse = new SimpleStringProperty("asdasdasd");
this.adresseUnterkunft = new SimpleStringProperty("asdasdasd");
this.visum = new SimpleStringProperty("asdasdasd");
this.impfstatus = new SimpleStringProperty("asdasdasd");
this.Sprachniveau = new SimpleStringProperty("asdasdasd");
this.berufstätig = new SimpleStringProperty("asdasdasd");
this.facharzt = new SimpleStringProperty("asdasdasd");
this.approbation = new SimpleStringProperty("asdasdasd");
this.studium = new SimpleStringProperty("asdasdasd");
this.bundesland = new SimpleStringProperty("asdasdasd");
this.sprachkurs = new SimpleStringProperty("asdasdasd");
this.arbeitsbegin = new SimpleStringProperty("asdasdasd");
this.erhaltRate = new SimpleStringProperty("asdasdasd");
this.anmerkungen = new SimpleStringProperty("asdasdasd");
}
// getters and setters
Assuming your getters and setters are correct, you probably forgot to set the on-action function of your button.
You can do that in your fxml file by adding an "onAction" argument like this:
<Button text="Save" onAction=#saveTextfield/>
Or you can do that in your SceneBuilder like this:
If this is not the problem, maybe show your getters and setters, and provide a minimal reproducable example.
(I should probably write this as a comment and not an answer, but I don't have 50 rep yet.)

how do I reference a list array I created in a different class into a another 2

This is where i created the arraylist
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.control.TextField;
import javafx.scene.control.Button;
import javafx.event.ActionEvent;
import sample.Data.Students;
import java.io.IOException;
import java.util.ArrayList;
public class StudentEnrollment {
public static ArrayList<Students> SDetails=new ArrayList<Students>();
public static String StuID="";
#FXML
private Button studentenrollmentnextbtn;
#FXML
private TextField studentenrollmentname;
#FXML
private TextField studentenrollmentid;
#FXML
private TextField studentenrollmentage;
#FXML
private TextField studentenrollmentnum;
public void StudentEnroll(ActionEvent m)throws IOException{
Students s=new Students();
s.setSname(studentenrollmentname.getText());
s.setSid(studentenrollmentid.getText());
StuID=studentenrollmentid.getText();
s.setSage(Integer.parseInt(studentenrollmentage.getText()));
s.setSnumber(Integer.parseInt(studentenrollmentnum.getText()));
SDetails.add(s);
Parent root= FXMLLoader.load(getClass().getResource("AdminEnterDetails.fxml"));
Scene scene = new Scene(root);
Stage stage= (Stage)((Node)m.getSource()).getScene().getWindow();
stage.setScene(scene);
stage.show();
}
}
and this is my student class
package sample.Data;
public class Students {
private String Sid;
private String Sname;
private int Sage;
private int Snumber;
public String getSid() {
return Sid;
}
public void setSid(String sid) {
Sid = sid;
}
public String getSname() {
return Sname;
}
public void setSname(String sname) {
Sname = sname;
}
public int getSage() {
return Sage;
}
public void setSage(int sage) {
Sage = sage;
}
public int getSnumber() {
return Snumber;
}
public void setSnumber(int snumber) {
Snumber = snumber;
}
}
this is where i want to use the arraylist,i want use it here because,i want to check whether my arraylist is empty,if its empyt i want to show a error message and if its not empty i want to search the ID that i entered in that arraylist
public class StudentLogin {
StudentEnrollment = new StudentEnrollment();
ArrayList<Students> list = number.getList();
#FXML
private Label error;
#FXML
private TextField studentuserid;
#FXML
private Button studentloginbtn;
public void ViewbyStudent(ActionEvent e) throws IOException {
if()
for(Students m:StudentEnrollment.SDetails)
if(Objects.equals(m.getSid(),studentuserid.getText())){
Parent root= FXMLLoader.load(getClass().getResource("ViewStudentDetails.fxml"));
Scene scene = new Scene(root);
Stage stage= (Stage)((Node)e.getSource()).getScene().getWindow();
stage.setScene(scene);
stage.show();
}else{
error.setText("Student ID you entered is incorrec,\n or ID couldn't be found,PLEASE TRY AGAIN");
}
}
}
StudentEnrollment.SDetails.isEmpty();
You are very close. ArrayLists have a built in isEmpty() method that will return a boolean value true/false depending whether or not the list is empty.
So, assuming that your empty if() is where you need your logic to go, your ViewbyStudent() method would look something like this:
public void ViewbyStudent(ActionEvent e) throws IOException {
if(!studentEnrollment.SDetails.isEmpty()) {
for (Students m : StudentEnrollment.SDetails)
if (Objects.equals(m.getSid(), studentuserid.getText())) {
Parent root = FXMLLoader.load(getClass().getResource("ViewStudentDetails.fxml"));
Scene scene = new Scene(root);
Stage stage = (Stage) ((Node) e.getSource()).getScene().getWindow();
stage.setScene(scene);
stage.show();
} else {
error.setText("Student ID you entered is incorrec,\n or ID couldn't be found,PLEASE TRY AGAIN");
}
} else {
error.setText("Oh no! SDetails is empty!");
}
}
So basically if the list is NOT empty (that's what the ! is) it will execute the code block you already had, but now if the list IS empty it will simply set the text to "Oh no! SDetails is empty!"

JavaFX use parsed variables during initialize

I know how to parse variables to controllers in JavaFX with fxml. But i need to use them in the initialize method of my controller. Is there a ways to do this? The background is, that i have a interface, where you can define different settings. Now you can safe them and have to be able to reopen them. So now when i open a rule, i need to set the values in the new option view. I know, that it works on text fields (UI-Elements) to set Text during initialize but not for variables. I tried different approaches. Like binding with properties (works for visibility property of button (UI-Element) but not for variables to set. Do you know a way or maybe an other approach?
Here is my example:
Controller1:
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Stage;
/**
*
* #author Sandro
*/
public class FXMLDocumentController implements Initializable {
#FXML
private Button btn_openWindow;
#FXML
private void handleButtonAction(ActionEvent event) {
try {
Stage stage = new Stage();
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(getClass().getResource("fxml_second.fxml").openStream());
Fxml_secondController cont = (Fxml_secondController)loader.getController();
cont.setFlag(0x00000002);
cont.setIsChange(false);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
btn_openWindow.setOnAction(this::handleButtonAction);
}
Controller 2:
/**
* FXML Controller class
*
* #author Sandro
*/
public class Fxml_secondController implements Initializable {
#FXML private Button btn_printOut;
private boolean isChange = true;
private int flag = 0x00000001;
private void printOut(ActionEvent event){
System.out.println("isChange: "+isChange);
System.out.println("flag: "+flag);
}
public boolean isIsChange() {
return isChange;
}
public void setIsChange(boolean isChange) {
this.isChange = isChange;
}
public int getFlag() {
return flag;
}
public void setFlag(int flag) {
this.flag = flag;
}
#Override
public void initialize(URL url, ResourceBundle rb) {
btn_printOut.setOnAction(this::printOut);
System.out.println(flag);
}
In controller 2 you see the problem. The console-output in initialize shows 1 but it need to show 2. If i klick on printOut (Button) it prints out the right values which i have set in Controller 1.
Set the controller in the Java code, instead of in FXML.
Remove the fx:controller attribute from fxml_second.fxml, and change the code in FXMLDocumentController as follows:
#FXML
private void handleButtonAction(ActionEvent event) {
try {
Stage stage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("fxml_second.fxml"));
Fxml_secondController cont = new Fxml_secondController();
cont.setFlag(0x00000002);
cont.setIsChange(false);
loader.setController(cont);
Parent root = loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
Another option would be to use a custom component approach for the second fxml.

PieChart (JavaFx) didn't display my Label on Event - JavaFx

I try to create a label on click for my PieChart, but unfortunately my label is never visible.
I found a similar topic on StackOverFlow : Label not showing on mouse event JavaFx
But my application is not as simple. I can't add my Label to the list of children because of my architecture.
(You can found a diagram here : http://i.stack.imgur.com/ZFJaR.png )
Here my code :
PieChartNode.java
package nodeStatsVision.chartFactory;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import nodeStatsVision.beans.ListRepere;
import nodeStatsVision.beans.OptionsChart;
import nodeStatsVision.beans.ValueStat;
/**
*
* #author Zombkey.
*/
public class PieChartNode implements ChartNode {
private ListRepere categories;
private ArrayList<ValueStat> values;
private ObservableList<PieChart.Data> pieChartData;
private Node node;
public PieChartNode(ListRepere categories, ArrayList<ValueStat> values){
this.categories = categories;
this.values = values;
pieChartData = FXCollections.observableArrayList();
node = new PieChart(pieChartData);
Platform.runLater(new Runnable() {
#Override
public void run() {
formatData();
}
});
}
private void formatData() {
final Label caption = new Label("");
caption.setTextFill(Color.DARKORANGE);
caption.setStyle("-fx-font: 24 arial;");
for(ValueStat v : values){
PieChart.Data dataTemp = new PieChart.Data(v.getCategorie().getStringName(),v.getDoubleValue());
pieChartData.add(dataTemp);
dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
System.out.println("event : "+v.getCategorie().getStringName()+" : "+v.getDoubleValue());
caption.setTranslateX(e.getSceneX());
caption.setTranslateY(e.getSceneY());
caption.setText(String.valueOf(dataTemp.getPieValue()));
caption.setVisible(true);
System.out.println("label "+caption);
}
});
}
}
#Override
public Node getNodeGraph() {
return node;
}
#Override
public void setOptions(OptionsChart optionsChart) {
//To implemente
}
}
Have you a idea about, how add my Label to the scene ?
Thanks !
(Other question, Why the Node of PieChart.Data is on ReadOnly ?)
Zombkey.
PS : Sorry about my english, I'm a French student, I'm still learning :)
Ps 2 : First time on StackOverflow, if I did mistake, tell me it !
Ok ! I found a solution for my case !
Semantically my Label is only for my PieChart. That's why I don't want had it to my SceneGraph.
My ChartFactory return a Node, then display it. So my node have to contain the PieChart AND the Label.
I create a Group with a StackPane. In the StackPane I add my PieChart and my Label. Then my factory return the Group as a Node.
Drop the code !
package nodeStatsVision.chartFactory;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.chart.PieChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import nodeStatsVision.beans.ListRepere;
import nodeStatsVision.beans.OptionsChart;
import nodeStatsVision.beans.ValueStat;
/**
*
* #author Zombkey.
*/
public class PieChartNode implements ChartNode {
private ListRepere categories;
private ArrayList<ValueStat> values;
private ObservableList<PieChart.Data> pieChartData;
private Group group;
private Node node;
private final Label caption;
public PieChartNode(ListRepere categories, ArrayList<ValueStat> values){
this.categories = categories;
this.values = values;
group = new Group();
StackPane pane = new StackPane();
group.getChildren().add(pane);
pieChartData = FXCollections.observableArrayList();
node = new PieChart(pieChartData);
pane.getChildren().add(node);
caption = new Label("");
caption.setVisible(false);
caption.getStyleClass().addAll("chart-line-symbol", "chart-series-line");
caption.setStyle("-fx-font-size: 12; -fx-font-weight: bold;");
caption.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
pane.getChildren().add(caption);
Platform.runLater(new Runnable() {
#Override
public void run() {
formatData();
}
});
}
private void formatData() {
for(ValueStat v : values){
PieChart.Data dataTemp = new PieChart.Data(v.getCategorie().getStringName(),v.getDoubleValue());
pieChartData.add(dataTemp);
dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_ENTERED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
caption.setTranslateX(e.getX());
caption.setTranslateY(e.getY());
caption.setText(String.valueOf(dataTemp.getPieValue()));
caption.setVisible(true);
}
});
dataTemp.getNode().addEventHandler(MouseEvent.MOUSE_EXITED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
caption.setVisible(false);
}
});
}
}
#Override
public Node getNodeGraph() {
return (Node)group;
}
#Override
public void setOptions(OptionsChart optionsChart) {
//To implemente
}
}
Thanks #eckig for your answers !
You create and style your Label named caption but never add it to the SceneGraph.
Somewhere it has to be added to a Parent element, otherwise it will not get displayed.
Your PieChart gets added to a parent element, otherwise it will not be displayed. The same way goes for all other JavaFX Nodes.
As to your second question, read the JavaDocs:
Readonly access to the node that represents the pie slice. You can use this to add mouse event listeners etc.
You could use Tooltip to display a value:
for (final PieChart.Data temp : pieChart.getData()) {
Tooltip tooltip = new Tooltip(String.valueOf(temp.getPieValue()));
Tooltip.install(temp.getNode(), tooltip);
}

Categories