Preventing duplicate entries in ObservableList - javafx

I can't seem to get it right. I have a listbox with category items. I also have a data model that defines the ID, Name, Lastname, Category.. and an ObservableList that holds the data. I'm trying to update the existing object in case the user click on the same item in the listbox and change name, lastname.
Here is my code:
public class FXMLDocController implements Initializable {
ObservableList<String> listitems = FXCollections.observableArrayList(
"Visual Basic", "ASP.net", "JavaFX");
ObservableList<Persons> personData = FXCollections.observableArrayList();
Persons pp = new Persons();
private Label label;
#FXML
private TextField txtName;
#FXML
private TextField txtLastName;
#FXML
private Button btnSave;
#FXML
private TextArea txtArea;
#FXML
private ListView<String> listview = new ListView<String>();
#FXML
private Button btnTest;
#FXML
private Label lblCategory;
#FXML
private Label lblIndex;
#Override
public void initialize(URL url, ResourceBundle rb) {
listview.setItems(listitems);
}
#FXML
private void handleSave(ActionEvent event) {
String category = lblCategory.getText();
boolean duplicate = false;
//Add data. Check first if personData is empty
if (personData.isEmpty()){
pp = new Persons(Integer.valueOf(lblIndex.getText()),category,txtName.getText(),txtLastName.getText());
personData.add(pp);
}else{
for(int i = 0 ; i<personData.size() ; i ++){
if(Integer.toString(personData.get(i).getID()).equals(lblIndex.getText())){
duplicate = true;
}else{
duplicate = false;
}
}
System.out.println(duplicate);
if (duplicate == false){
pp = new Persons(Integer.valueOf(lblIndex.getText()),category,txtName.getText(),txtLastName.getText());
personData.add(pp);
}else{
System.out.println("Duplicate");
// Do Update later.
}
}
//Show data to Test
System.out.println("-- START OF LIST --");
for (Persons person : personData){
System.out.println(person.getID() + " " + person.getCategory()+ " " + person.getName() + " " + person.getLastname() + " " );
}
System.err.println(" ");
}
#FXML
private void handleListClick(MouseEvent event) {
lblCategory.setText(listview.getSelectionModel().getSelectedItem());
lblIndex.setText(String.valueOf(listview.getSelectionModel().getSelectedIndex()));
}
}
If I click multiple times on one item on the listbox it works well.. but if for example I click on Visual Basic, then ASP.net the go back to Visual Basic it still accepts it. :(
Need advice and help. Please
Here is the code based on Phil's suggestion
#FXML
private void handleSave(ActionEvent event) {
String category = lblCategory.getText();
boolean duplicate = false;
int x = 0;
//Add data
Persons newPerson = new Persons(Integer.valueOf(lblIndex.getText()), category, txtName.getText(), txtLastName.getText());
if (!personData.contains(newPerson)) {
personData.add(newPerson);
}else{
System.out.println("Duplicate!");
}
//Show data
System.out.println("-- START OF LIST --");
for (Persons person : personData){
System.out.println(person.getID() + " " + person.getCategory()+ " " + person.getName() + " " + person.getLastname() + " " );
}
}
here's my Persons Class
public class Persons {
private SimpleIntegerProperty id;
private SimpleStringProperty name;
private SimpleStringProperty lastname;
private SimpleStringProperty category;
public Persons(){}
public Persons(int id, String category, String name, String lastname){
this.id = new SimpleIntegerProperty(id);
this.name = new SimpleStringProperty(name);
this.lastname = new SimpleStringProperty(lastname);
this.category = new SimpleStringProperty(category);
}
public Persons(String name, String lastname){
this.name = new SimpleStringProperty(name);
this.lastname = new SimpleStringProperty(lastname);
}
#Override
public boolean equals(Object o){
if (o == this) return true;
if (!(o instanceof Persons)){
return false;
}
Persons persons = (Persons) o;
return persons.id.equals(id) &&
persons.name.equals(name) &&
persons.lastname.equals(lastname) &&
persons.category.equals(category);
}
//SETTERS
public void setID(int id) {
this.id = new SimpleIntegerProperty(id);
}
public void setName(String name) {
this.name = new SimpleStringProperty(name);
}
public void setLastname(String lastname) {
this.lastname = new SimpleStringProperty(lastname);
}
public void setCategory(String category) {
this.category = new SimpleStringProperty(category);
}
//GETTERS
public int getID() {
return id.getValue();
}
public String getName() {
return name.getValue();
}
public String getLastname() {
return lastname.getValue();
}
public String getCategory(){
return category.getValue();
}
// PROPERTIES
public SimpleIntegerProperty idProperty(){
return this.id;
}
public SimpleStringProperty nameProperty(){
return this.name;
}
public SimpleStringProperty lastnameProperty(){
return this.lastname;
}
public SimpleStringProperty categoryProperty(){
return this.category;
}
}

Ok, this looks good. Just one little thing in your equals implementation:
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Persons)) {
return false;
}
Persons persons = (Persons) o;
// persons.id.equals() leads to the default implementation in Object
// --> instead use this one.
// The Property classes have their own isEqualTo method
// with get(), you will get your simple boolean from the returned BooleanBinding
return persons.id.isEqualTo(id).get() &&
persons.name.isEqualTo(name).get() &&
persons.lastname.isEqualTo(lastname).get() &&
persons.category.isEqualTo(category).get();
}
The default equals implementation from Object just compares if it is the same instance. And we are creating a new instance and check with contains(...) if the list contains the Persons.
Here is the whole code I used to test it:
public class Main extends Application {
private ObservableList<String> listitems = FXCollections.observableArrayList("Visual Basic", "ASP.net", "JavaFX");
private ObservableList<Persons> personData = FXCollections.observableArrayList();
private TextField txtName = new TextField();
private TextField txtLastName = new TextField();
private Button btnSave = new Button("save");
private ListView<String> listview = new ListView<>();
private Label lblCategory = new Label();
private Label lblIndex = new Label();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
listview.setItems(listitems);
listview.setOnMouseClicked(this::handleListClick);
btnSave.setOnAction(this::handleSave);
VBox vb = new VBox(new HBox(5, new Label("Index:"), lblIndex),
new HBox(5, new Label("Category:"), lblCategory),
new HBox(5, new Label("Name:"), txtName),
new HBox(5, new Label("Last name:"), txtLastName)
);
BorderPane bp = new BorderPane();
bp.setLeft(listview);
bp.setCenter(vb);
bp.setRight(btnSave);
Scene scene = new Scene(bp, 600, 400);
stage.setScene(scene);
stage.show();
}
private void handleSave(ActionEvent event) {
Persons newPerson = new Persons(Integer.valueOf(lblIndex.getText()), lblCategory.getText(), txtName.getText(), txtLastName.getText());
if (!personData.contains(newPerson)) {
personData.add(newPerson);
} else {
System.out.println("Duplicate!");
}
System.out.println("-- START OF LIST --");
for (Persons person : personData) {
System.out.println(person);
}
}
private void handleListClick(MouseEvent event) {
System.out.println("click");
lblCategory.setText(listview.getSelectionModel().getSelectedItem());
lblIndex.setText(String.valueOf(listview.getSelectionModel().getSelectedIndex()));
}
public class Persons {
SimpleIntegerProperty id;
SimpleStringProperty name;
SimpleStringProperty lastname;
SimpleStringProperty category;
Persons(int id, String category, String name, String lastname) {
this.id = new SimpleIntegerProperty(id);
this.name = new SimpleStringProperty(name);
this.lastname = new SimpleStringProperty(lastname);
this.category = new SimpleStringProperty(category);
}
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Persons)) {
return false;
}
Persons persons = (Persons) o;
// persons.id.equals() leads to the default implementation in Object
// --> instead use this one.
// The Property classes have their own isEqualTo method
// with get(), you will get your simple boolean from the returned BooleanBinding
return persons.id.isEqualTo(id).get() &&
persons.name.isEqualTo(name).get() &&
persons.lastname.isEqualTo(lastname).get() &&
persons.category.isEqualTo(category).get();
}
#Override
public String toString() {
return "Persons{" +
"id=" + id +
", name=" + name +
", lastname=" + lastname +
", category=" + category +
'}';
}
}
}

Related

JavaFX tableView not showing data even though the data is being populated properly

I'm Actually new with JavaFX and been facing an issue to view the data on the table.
What I'm trying to do is to create a new stage on a Mouse Click Event of an Imageview where the Fields will be provided to the user to enter the data to the table on the parent node.
This is the function which is called on the mouse click event that creates a child node(stage) :
private void addQualification(MouseEvent event) {
System.out.println("Add Qualification Method");
final Stage dialog = new Stage();
dialog.setTitle("Add a Qualification");
dialog.initModality(Modality.WINDOW_MODAL);
dialog.initStyle(StageStyle.UTILITY);
// create a grid for the data entry.
GridPane grid = new GridPane();
AnchorPane anchorPane = new AnchorPane(grid);
ObservableList<String> QualChoiceList = FXCollections.observableArrayList("MBBS/MSC ", "MD/MS/DNB/PhD", "DM/M Ch.");
final ChoiceBox<String> QualChoice = new ChoiceBox<String>();
QualChoice.setValue("Select a Qualification");
QualChoice.setItems(QualChoiceList);
final TextField College = new TextField();
final TextField University = new TextField();
final TextField PassingYear = new TextField();
final TextField RegNo = new TextField();
final TextField StateName = new TextField();
grid.addRow(0, new Label("Qualification"), QualChoice);
grid.addRow(1, new Label("College"), College);
grid.addRow(2, new Label("University"), University);
grid.addRow(3, new Label("Year of Passing"), PassingYear);
grid.addRow(4, new Label("Registration No."), RegNo);
grid.addRow(5, new Label("Name of State"), StateName);
grid.setHgap(10);
grid.setVgap(10);
GridPane.setHgrow(QualChoice, Priority.ALWAYS);
GridPane.setHgrow(College, Priority.ALWAYS);
GridPane.setHgrow(University, Priority.ALWAYS);
GridPane.setHgrow(PassingYear, Priority.ALWAYS);
GridPane.setHgrow(RegNo, Priority.ALWAYS);
GridPane.setHgrow(StateName, Priority.ALWAYS);
// create action buttons for the dialog.
Button ok = new Button("Add");
Button cancel = new Button("Cancel");
ok.setDefaultButton(true);
cancel.setCancelButton(true);
anchorPane.getChildren().add(ok);
anchorPane.getChildren().add(cancel);
AnchorPane.setTopAnchor(grid, 20.0);
AnchorPane.setLeftAnchor(grid, 20.0);
AnchorPane.setRightAnchor(grid, 20.0);
AnchorPane.setBottomAnchor(grid, 80.0);
AnchorPane.setTopAnchor(ok, 240.0);
AnchorPane.setLeftAnchor(ok, 100.0);
AnchorPane.setRightAnchor(ok, 214.0);
AnchorPane.setBottomAnchor(ok, 30.0);
AnchorPane.setTopAnchor(cancel, 240.0);
AnchorPane.setLeftAnchor(cancel, 230.0);
AnchorPane.setRightAnchor(cancel, 95.0);
AnchorPane.setBottomAnchor(cancel, 30.0);
dialog.setScene(new Scene(anchorPane, 400, 310));
dialog.show();
// only enable the ok button when there has been some text entered.
ok.disableProperty().bind(College.textProperty().isEqualTo("").or(University.textProperty().isEqualTo("")).or(PassingYear.textProperty().isEqualTo("")).or(RegNo.textProperty().isEqualTo("")).or(StateName.textProperty().isEqualTo("")));
// add action handlers for the dialog buttons.
ok.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
int nextIndex = QualTable.getSelectionModel().getSelectedIndex() + 1;
QualTable.getItems().add(nextIndex, new Qualification(QualChoice.getValue(), College.getText(), University.getText(), PassingYear.getText(), RegNo.getText(), StateName.getText()));
QualTable.getSelectionModel().select(nextIndex);
dialog.close();
}
});
cancel.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
dialog.close();
}
});
This is the Qualification Class that I have used to inout the values to the QualTable using the add Method:
public static class Qualification {
private StringProperty Qual;
private StringProperty College;
private StringProperty University;
private StringProperty PassingYear;
private StringProperty RegNo;
private StringProperty StateName;
public Qualification(String Qual, String College, String University, String PassingYear, String RegNo, String StateName) {
setQual(Qual);
setCollege(College);
setUniversity(University);
setPassingYear(PassingYear);
setRegNo(RegNo);
setStateName(StateName);
}
public String getQual() {
return QualProperty().get();
}
public String getCollege() {
return CollegeProperty().get();
}
public String getUniversity() {
return UniversityProperty().get();
}
public String getPassingYear() {
return PassingYearProperty().get();
}
public String getRegNo() {
return RegNoProperty().get();
}
public String getStateName() {
return StateNameProperty().get();
}
public final void setQual(String value) {
QualProperty().set(value);
}
public final void setCollege(String Coll) {
CollegeProperty().set(Coll);
}
public final void setUniversity(String Univ) {
UniversityProperty().set(Univ);
}
public final void setPassingYear(String PsngYr) {
PassingYearProperty().set(PsngYr);
}
public final void setRegNo(String Reg) {
RegNoProperty().set(Reg);
}
public final void setStateName(String StNm) {
StateNameProperty().set(StNm);
}
public StringProperty QualProperty() {
if (Qual == null) {
Qual = new SimpleStringProperty(this, "Qual");
}
return Qual;
}
public StringProperty CollegeProperty() {
if (College == null) {
College = new SimpleStringProperty(this, "College");
}
return College;
}
public StringProperty UniversityProperty() {
if (University == null) {
University = new SimpleStringProperty(this, "University");
}
return University;
}
public StringProperty PassingYearProperty() {
if (PassingYear == null) {
PassingYear = new SimpleStringProperty(this, "PassingYear");
}
return PassingYear;
}
public StringProperty RegNoProperty() {
if (RegNo == null) {
RegNo = new SimpleStringProperty(this, "RegNo");
}
return RegNo;
}
public StringProperty StateNameProperty() {
if (StateName == null) {
StateName = new SimpleStringProperty(this, "StateName");
}
return StateName;
}
}
This is the FXML code of the Anchor Pane consisting the tableview QualTable
I Need help on this tableview and the function that I'm using to populate the table view...
The values are properly carried through the Qualification class but the tableview is not displaying the values on the row....
Please help me out through this and Thanks in Advance..!!!

Passing values between controllers by using the view object - JavaFX

When generating a multi view project with Gluon plugin for Ecplise, Netbeans or Intellij. It will be generating a view-class and a presenter-class. The view class looks like this for example:
public class ModelsView {
public View getView() {
try {
View view = FXMLLoader.load(ModelsView.class.getResource("models.fxml"));
return view;
} catch (IOException e) {
System.out.println("IOException: " + e);
return new View();
}
}
}
Is there some way I can access all the private fields in this controller models.fxml by just creating a code line like this:
View view = new ModelsView().getView(); // Here I am inside another controller
Can I access for example the getter method from the presenter-class by using the view object ? The view object is static as I can see it because there is no new before FXMLLoader.load(URL location)
public class ModelsPresenter {
#FXML
private View models;
#FXML
private #Getter TableView<String> tableView;
public void initialize() {
}
}
Heretic I am not using JavaFX from Gluon my configuration is jdk1.8.0_191 with derby in Netbeans 8.2 The code I am posting is my Model class PWData and the TableViewController just grabs the data from the derby DB The real important code is the initialize section of the TableViewController
public class PWData {
private final StringProperty ID;
private final StringProperty website;
private final StringProperty un;
private final StringProperty pw;
private final StringProperty sq;
private final StringProperty sans;
private final StringProperty notes;
public PWData(String ID,String website,String un,String pw,String sq,String sans,String notes) {
this.ID = new SimpleStringProperty(ID);
this.website = new SimpleStringProperty(website);
this.un = new SimpleStringProperty(un);
this.pw = new SimpleStringProperty(pw);
this.sq = new SimpleStringProperty(sq);
this.sans = new SimpleStringProperty(sans);
this.notes = new SimpleStringProperty(notes);
}
public String getID() {// 0
return ID.get();
}
public void setID(String ID){// 0
this.ID.set(ID);
}
public StringProperty IDProperty(){// 0
return ID;
}
public String getWebSite() {// 1
return website.get();
}
public void setwebsite(String website){// 1
this.website.set(website);
}
public StringProperty websiteProperty(){// 1
return website;
}
public String getUNName() {// 2
return un.get();
}
public void setun(String un){// 2
this.un.set(un);
}
public StringProperty unProperty(){// 2
return un;
}
public String getPW() {// 3
return pw.get();
}
public void setpw(String pw){// 3
this.pw.set(pw);
}
public StringProperty pwProperty(){// 3
return pw;
}
public String getSQName() {// 4
return sq.get();
}
public void setsq(String sq){// 4
this.sq.set(sq);
}
public StringProperty sqProperty(){// 4
return sq;
}
public String getSANS() {// 5
return sans.get();
}
public void setsans(String sans){// 5
this.sans.set(sans);
}
public StringProperty sansProperty(){// 5
return sans;
}
public String getNotes() {// 6
return notes.get();
}
public void setnotes(String notes){// 6
this.notes.set(notes);
}
public StringProperty notesProperty(){// 6
return notes;
}
public class TableViewController implements Initializable {
#FXML Pane tableviewPane,signinPane,detailviewPane;
#FXML private TableView<PWData> table;// NOTE CONSTRUCTION see Observable Value
#FXML private TableColumn<PWData,String> IDCol;
#FXML private TableColumn<PWData,String> websiteCol;
#FXML private TableColumn<PWData,String> unCol;
#FXML private TableColumn<PWData,String> pwCol;
String SQL_PWDataTable = "create table PWData ("
+ "ID int not null generated always as identity "
+ " (start with 100,increment by 1),"
+ "website varchar(50) not null, un varchar(40) not null, "
+ "pw varchar(40) not null, sq varchar(80) not null, "
+ "sans varchar(80) not null, notes varchar(260) not null,"
+ "primary key (ID) )";
String dbName="PWKeep";
public Stage stage;
String conURL = "jdbc:derby:C:/A_DerbyPWKeeper/DBName/" + dbName;
public static String strID;
KeyCode kc;
#FXML
private void onPress(KeyEvent ev) throws IOException{
kc = ev.getCode();
if(kc == KeyCode.ESCAPE){
onBack(null);
}
}
private void MakeTable() throws SQLException, IOException{
if (!tableExists( SignInController.con, "PWData")){
//System.out.println ("Creating table PWData");
SignInController.stmnt = SignInController.con.createStatement();
SignInController.stmnt.execute(SQL_PWDataTable );
SignInController.stmnt.close();
}else{
//System.out.println("PWData already created");
}
ReadFromDB();
}
// Does the table EXISTS
private static boolean tableExists ( Connection con, String table ) {
int numRows = 0;
try {
DatabaseMetaData dbmd = con.getMetaData();
// Note the args to getTables are case-sensitive!
ResultSet rs = dbmd.getTables( null, "APP", table.toUpperCase(), null);
while( rs.next()) ++numRows;
}catch(SQLException e){
String theError = e.getSQLState();
System.out.println("Can't query DB metadata: " + theError );
System.exit(1);
}
return numRows > 0;
}
private void ReadFromDB() throws SQLException{
SignInController.stmnt = SignInController.con.createStatement();
ObservableList<PWData> TableData = FXCollections.observableArrayList();
try (ResultSet rs = SignInController.stmnt.executeQuery("SELECT * FROM PWData") // Get all DB data
//int rowCount = 0;
) {
while (rs.next()){// Add data to observableArrayList TableData
//rowCount++;
TableData.add(new PWData(rs.getString("ID"),rs.getString("website")
,rs.getString("un"),rs.getString("pw"),rs.getString("sq"),rs.getString("sans"),rs.getString("notes")));
} //System.out.println("Row Count "+rowCount);// Useful for Printing for further development
PropertyValueFactory<PWData, String> IDCellValueFactory = new PropertyValueFactory<>("ID");
IDCol.setCellValueFactory(IDCellValueFactory);
PropertyValueFactory<PWData, String> WebSiteCellValueFactory = new PropertyValueFactory<>("website");
websiteCol.setCellValueFactory(WebSiteCellValueFactory);
PropertyValueFactory<PWData, String> UNCellValueFactory = new PropertyValueFactory<>("un");
unCol.setCellValueFactory(UNCellValueFactory);
PropertyValueFactory<PWData, String> PWCellValueFactory = new PropertyValueFactory<>("pw");
pwCol.setCellValueFactory(PWCellValueFactory);
Collections.sort(TableData, (p1, p2)-> p1.getWebSite().compareToIgnoreCase(p2.getWebSite()));
// Line of Code above Sorts websiteCol alpha
if(TableData.size() < 14) {// Format TableView to display Vertical ScrollBar
table.setPrefWidth(838);
}else {
table.setPrefWidth(855);
} table.setItems(TableData);
SignInController.stmnt.close();
}
}
#FXML
private void onBack(ActionEvent e) throws IOException{
stage = (Stage)tableviewPane.getScene().getWindow();
signinPane = FXMLLoader.load(getClass().getResource("signin.fxml"));
Scene scene = new Scene(signinPane);
scene.getStylesheets().add(getClass().getResource("pwkeeper.css").toExternalForm());
stage.setScene(scene);
stage.show();
stage.sizeToScene();
stage.centerOnScreen();
}
#FXML
private void onAdd(ActionEvent e) throws IOException{
stage = (Stage)tableviewPane.getScene().getWindow();
detailviewPane = FXMLLoader.load(getClass().getResource("detailview.fxml"));
Scene scene = new Scene(detailviewPane);
scene.getStylesheets().add(getClass().getResource("pwkeeper.css").toExternalForm());
stage.setScene(scene);
stage.show();
stage.sizeToScene();
stage.centerOnScreen();
}
private void MakeConn() throws SQLException, IOException{
SignInController.con = DriverManager.getConnection(conURL);
}
#FXML // This DROPS the MasterPW TABLE when the Reset Password is selected
private void onDrop(ActionEvent e) throws SQLException, IOException{
SignInController.stmnt = SignInController.con.createStatement();
SignInController.stmnt.executeUpdate("DROP TABLE MasterPW");
SignInController.stmnt.close();
onBack(null);
}
private void showTableDataDetails(PWData info) throws IOException{
if (info != null) {
info = (PWData) table.getSelectionModel().getSelectedItem();
strID = info.getID();
onAdd(null);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
try {
MakeTable();
} catch (SQLException | IOException ex) {
Logger.getLogger(TableViewController.class.getName()).log(Level.SEVERE, null, ex);
}
table.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends PWData>
observable,PWData oldValue, PWData newValue) -> {
try {
showTableDataDetails((PWData) newValue); // When a row of the table is Selected call
// Proper Construction // showTableDataDetails method
} catch (IOException ex) {
Logger.getLogger(TableViewController.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
I am a little unsure of what you are trying to do but I would suggest you focus on the use of ObservableValue and Listeners You can download the entire code
At GitHub HERE

Using a static nested class insted of toString

I have this task:
"We do not want to rely on us Currency their toString() for how a currency is displayed in list our. We will be able to set this up ourselves.
Create a static nested class called "Currency Cell" in ValutaOversikController as extender List Cell <Value>.
Override methods updateItem (Currency and Currency, boolean empty).
Set how a currency should be presented in the list e.g. "Country - Currency Code"
Then put CellFactory for our ListView, which returns an instance of the new Currency Cell class."
I started to make the last method in Controller, but don't know if this is correct. As of now this is what I have:
public class Controller {
#FXML
private ComboBox<Valuta> listeMedValutaerEn, listeMedValutaerTo;
#FXML
private ComboBox<Sorteringen> listeMedSortering;
#FXML
private TextField textFieldValutaerEn, textFieldValutaerTo;
#FXML
private ImageView imageViewValutaerEn, imageViewValutaerTo;
#FXML
public void initialize() {
listeMedValutaerEn.setItems(DataHandler.hentValutaData());
listeMedValutaerTo.setItems(DataHandler.hentValutaData());
listeMedSortering.setItems(DataHandler.hentSorteringsData());
listeMedValutaerEn.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Valuta>() {
#Override
public void changed(ObservableValue<? extends Valuta> observableValue, Valuta gammelValuta, Valuta nyValuta) {
fyllUtValutaEn(nyValuta);
}
});
listeMedValutaerTo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Valuta>() {
#Override
public void changed(ObservableValue<? extends Valuta> observableValue, Valuta gammelValuta, Valuta nyValuta) {
fyllUtValutaTo(nyValuta);
}
});
listeMedSortering.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Sorteringen>() {
#Override
public void changed(ObservableValue<? extends Sorteringen> observableValue, Sorteringen gammelSortering, Sorteringen nySortering) {
sortere(nySortering);
}
});
}
private void sortere(Sorteringen nySortering) {
ObservableList<Valuta> valutaSomSkalSorteres = DataHandler.hentValutaData();
CompareToValuta sortere = new CompareToValuta(nySortering.getSorteringsKode());
Collections.sort(valutaSomSkalSorteres, sortere);
listeMedValutaerEn.setItems(valutaSomSkalSorteres);
listeMedValutaerTo.setItems(valutaSomSkalSorteres);
}
private void fyllUtValutaEn(Valuta enValuta) {
if (enValuta != null) {
Image flaggEn = new Image("https://www.countryflags.io/" + enValuta.getLandskode() + "/shiny/64.png");
imageViewValutaerEn.setImage(flaggEn);
}
}
private void fyllUtValutaTo(Valuta enValuta) {
if (enValuta != null) {
Image flaggTo = new Image("https://www.countryflags.io/" + enValuta.getLandskode() + "/shiny/64.png");
imageViewValutaerTo.setImage(flaggTo);
}
}
#FXML
private void buttonBeregn(ActionEvent event) {
Integer valutaAntall = Integer.valueOf(textFieldValutaerEn.getText());
double valutaNrEn = listeMedValutaerEn.getSelectionModel().getSelectedItem().getValutakurs();
double valutaNrTo = listeMedValutaerTo.getSelectionModel().getSelectedItem().getValutakurs();
double valutaResultat = valutaAntall * (valutaNrEn / valutaNrTo);
textFieldValutaerTo.setText(String.valueOf(valutaResultat));
}
private static ListCell<Valuta> ValutaCelle() {
ListCell<Valuta> tja = new ListCell<>();
return tja;
}
}
Class DataHandler:
public class DataHandler {
private final static ObservableList<Valuta> valutaListe = FXCollections.observableArrayList();
private final static ObservableList<Sorteringen> sorteringsListe = FXCollections.observableArrayList();
public static ObservableList<Sorteringen> hentSorteringsData() {
if (sorteringsListe.isEmpty()) {
sorteringsListe.add(new Sorteringen("Sortere alfabetisk på land synkende", 1));
sorteringsListe.add(new Sorteringen("Sortere alfabetisk på land stigende", 2));
sorteringsListe.add(new Sorteringen("Sortere på valutakode, stigende", 3));
sorteringsListe.add(new Sorteringen("Sortere på valutakode, synkende", 4));
}
return sorteringsListe;
}
public static ObservableList<Valuta> hentValutaData() {
if (valutaListe.isEmpty()) {
valutaListe.addAll(genererValutaData());
}
return valutaListe;
}
private static ArrayList<Valuta> genererValutaData() {
File kilden = new File("src/no/hiof/aleksar/oblig5/valutakurser.csv");
ArrayList<Valuta> valutaerFraFiler = lesFraCSVFil(kilden);
return valutaerFraFiler;
}
private static ArrayList<Valuta> lesFraCSVFil(File filSomLesesFra) {
ArrayList<Valuta> valutaerFraFil = new ArrayList<>();
try (BufferedReader bufretLeser = new BufferedReader(new FileReader(filSomLesesFra))) {
String linje;
while( (linje = bufretLeser.readLine()) != null ){
String[] deler = linje.split(";");
Valuta enValuta = new Valuta(deler[0], deler[1], deler[2], Double.parseDouble(deler[3]));
valutaerFraFil.add(enValuta);
}
} catch (IOException e) {
System.out.println(e);
}
return valutaerFraFil;
}
}

Closing or hiding a stage with animation?

Ok, so I'm building this tiny JavaFX app and one of the things that have
bugged me was that while some of my stages would have that "enlarge-then-fade-out" animation on triggering close().
The close in particular is the last line of code in this code block:
#FXML
public void logout() throws SQLException {
Stage stage = ((Stage) logout_button.getScene().getWindow());
stage.close();
Main.loginStage.show();
}
Main.loginStage.close();
Here is that method's class
public class ListController {
#FXML private ImageView profImg;
#FXML private Button logout_button;
#FXML private TableView<Child> table;
#FXML private TableColumn col_name;
#FXML private TableColumn col_picture;
//TO BE MOVED TO EXTERNAL CLASS
private static Database db;
#FXML
public void initialize() {
db = new Database();
try {
initTable();
} catch (SQLException e){
System.out.println("loading failed");
}
initAvatar();
disableReorder();
}
private void initAvatar() {
profImg.setClip(ImageUtils.getAvatarCircle());
Image value = new Image("file:///" + GlobalInfo.getCurrProfImg().getAbsolutePath());
profImg.setImage(value);
}
public void initTable() throws SQLException {
db.init();
table.setRowFactory(new Callback<TableView<Child>, TableRow<Child>>() {
#Override
public TableRow<Child> call(TableView<Child> param) {
TableRow<Child> row = new TableRow<>();
row.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println(row.getItem().getId());
}
});
return row;
}});
table.setItems(db.getChildren());
col_picture.setCellValueFactory(new PropertyValueFactory<Child, File>("image"));
col_picture.setCellFactory(new Callback<TableColumn<Child, File>, TableCell<Child, File>>() {
#Override
public TableCell call(TableColumn param) {
return new TableCell<Child, File>() {
ImageView imageView = new ImageView();
Image childImage;
#Override
protected void updateItem(File item, boolean empty) {
if (item != null) {
childImage = new Image("file:///" + item.getAbsolutePath());
imageView.setImage(childImage);
imageView.setClip(ImageUtils.getAvatarCircle());
imageView.setFitHeight(65);
imageView.setFitWidth(65);
HBox hBox = new HBox(imageView);
hBox.setAlignment(Pos.CENTER);
setGraphic(hBox);
}
}
};
}
});
col_name.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Child, String>, ObservableValue>() {
#Override
public ObservableValue call(TableColumn.CellDataFeatures<Child, String> param) {
Child child = param.getValue();
String firstName = child.getfName();
String lastName = child.getlName();
String nickname = child.getNickname();
String placeholder = "PLACEHOLDER"; //Place holder for adding nickname if exists
String complete = firstName + placeholder + lastName;
//place nickname between first and last name if exists
if (nickname.length() != 0){
String nicknameString = " \"" + nickname + "\" ";
complete = complete.replace(placeholder, nicknameString);
//if nickname does not exist
} else {
complete = complete.replace(placeholder, "");
}
return new SimpleStringProperty(complete);
}
});
col_name.setCellFactory(new Callback<TableColumn<Child, String>, TableCell<Child, String>>() {
#Override
public TableCell call(TableColumn<Child, String> param) {
return new TableCell<Child, String>() {
#Override
protected void updateItem(String item, boolean empty) {
setText(item);
setAlignment(Pos.CENTER);
}
};
}
});
}
private void disableReorder() {
table.widthProperty().addListener((observable, oldValue, newValue) -> {
TableHeaderRow row = ((TableHeaderRow) table.lookup("TableHeaderRow"));
row.reorderingProperty().addListener((observable1, oldValue1, newValue1) -> row.setReordering(false));
}); //Fuck you oracle
}
#FXML
public void logout() throws SQLException {
Stage stage = ((Stage) logout_button.getScene().getWindow());
stage.close();
Main.loginStage.show();
}
#FXML
public void showSettings() throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/settings.fxml"));
SettingsStage stage = new SettingsStage();
stage.setOnHidden((event) -> {
SettingsStage settingsStage = ((SettingsStage) event.getSource());
if (settingsStage.getChange()) {
initialize();
}
});
Scene scene = new Scene(root, 600, 400);
stage.setScene(scene);
stage.setTitle("Settings");
stage.initModality(Modality.APPLICATION_MODAL);
stage.showAndWait();
}
#FXML
public void showChildForm(ActionEvent actionEvent) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/childForm.fxml"));
Parent root = loader.load();
ChildFormController controller = loader.getController();
controller.setListController(this);
Scene scene = new Scene(root, 575, 675);
scene.getStylesheets().add(getClass().getResource("/css/persistent-prompt.css").toExternalForm());
Stage stage = new Stage();
stage.setResizable(false);
stage.setScene(scene);
stage.setTitle("Add child");
stage.initModality(Modality.APPLICATION_MODAL);
stage.showAndWait();
}
}
However, I have some form stages which do not display this "animation" upon calling close() instead they simply disappear from the window, which I have found jarring.
Here is the code run to close one of these faulty stages, with its respective class further below:
#FXML
public void cancel(ActionEvent actionEvent) {
Stage stage = ((Stage) submitBtn.getScene().getWindow());
stage.close();
}
public class ChildFormController extends FormHelper {
#FXML
private ImageView childImage;
#FXML
private Label imageName;
#FXML
private PersistentPromptTextField firstNameInput;
#FXML
private PersistentPromptTextField lastNameInput;
#FXML
private PersistentPromptTextField nickNameInput;
#FXML
private PersistentPromptTextField birthPlaceInput;
#FXML
private PersistentPromptTextField referrerInput;
#FXML
private DatePicker birthDateInput;
#FXML
private DatePicker admissionDateInput;
#FXML
private Button submitBtn;
#FXML
private ComboBox childStatus;
//TWO SCOOPS TWO GENDERS TWO TERMS
#FXML
private ToggleGroup genderToggleGroup;
#FXML
private TextArea childDescInput;
#FXML
private Label warnEmptyLabel;
private FileInputStream slctdImgStrm;
private String pathRef;
private Parent nextParent;
private ChildParentsController childParentsController;
private ListController listController;
#FXML
public void initialize() throws FileNotFoundException {
//Init gender choice buttons and scene ref
//OMG MY PATRIARCHY
genderToggleGroup.getToggles().get(0).setSelected(true);
childStatus.getSelectionModel().selectFirst();
//Init default image for child
File defaultFile = new File("src\\main\\resources\\imgs\\default_avatar.png");
updateChosenImage(defaultFile);
//Init submit/next btn
initNextBtn();
childStatus.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> {
if (newValue.intValue() == 2) {
initSubmitBtn();
} else if (newValue.intValue() != 2 && oldValue.intValue() == 2) {
initNextBtn();
}
});
birthDateInput.valueProperty().addListener((observable, oldValue, newValue) -> {
if (admissionDateInput.getValue() != null) {
if (newValue.isAfter(admissionDateInput.getValue())) {
birthDateInput.setValue(admissionDateInput.getValue());
}
}
});
admissionDateInput.valueProperty().addListener(((observable, oldValue, newValue) -> {
if (birthDateInput.getValue() != null) {
if (admissionDateInput.getValue().isBefore(birthDateInput.getValue())) {
admissionDateInput.setValue(birthDateInput.getValue());
}
}
}));
}
private void initNextBtn() {
submitBtn.setText("Next");
submitBtn.getStyleClass().remove("submit");
submitBtn.getStyleClass().add("default");
submitBtn.setOnAction(event -> initParentForm());
}
private void initParentForm() {
if (formIsIncomplete())
return;
try {
if (nextParent == null) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/childParentsForm.fxml"));
Parent root = loader.load();
childParentsController = loader.getController();
setNextParent(root);
}
submitBtn.getScene().setRoot(nextParent);
childParentsController.setPrevRoot(submitBtn.getParent());
childParentsController.setChildFormController(this);
} catch (IOException e) {
e.printStackTrace();
DialogUtils.displayExceptionError(e, "Severe error!");
}
}
private void initSubmitBtn() {
submitBtn.setText("Submit");
submitBtn.getStyleClass().remove("default");
submitBtn.getStyleClass().add("submit");
submitBtn.setOnAction(event -> submit(true));
}
#FXML
public void cancel(ActionEvent actionEvent) {
Stage stage = ((Stage) submitBtn.getScene().getWindow());
stage.close();
}
/**
* Submits the child with all of its respecitve information
* #param active if this controller's scene is active
* #return id of child submitted, negative number if submission has failed
*/
public int submit(boolean active) {
if (formIsIncomplete())
return -1;
//Fetch first part of user input
String firstName = firstNameInput.getText();
String lastName = lastNameInput.getText();
String nickName = nickNameInput.getText();
String place_of_birth = birthPlaceInput.getText();
String childDesc = childDescInput.getText();
String referrer = referrerInput.getText();
int gender = genderToggleGroup.getToggles().indexOf(genderToggleGroup.getSelectedToggle());
int status = childStatus.getSelectionModel().getSelectedIndex();
//Get child's birthdate and admission_date date
LocalDate birthDate = birthDateInput.getValue();
LocalDate admissionDate = admissionDateInput.getValue();
//Fire up db helper and insert new child record
Database db = new Database();
//Retrieve record's ID for later use
int id;
try {
//Add record for child and retrieve its id
db.init();
db.addNewChild(firstName, lastName, nickName, place_of_birth, birthDate, childDesc, gender, referrer, status, admissionDate);
//Retrieve id for use in storing img
id = db.getChildIDOf(firstName, lastName, nickName, place_of_birth, birthDate, childDesc, gender, referrer, status, admissionDate);
if (id == -89) throw new SQLException();
File strgReg = new File(pathRef.replace("id", String.valueOf(id)));
//Store img file for child avatar
if (!(strgReg.exists() && strgReg.isFile())) {
strgReg.getParentFile().mkdirs();
strgReg.createNewFile();
}
Files.copy(slctdImgStrm, Paths.get(strgReg.getPath()), StandardCopyOption.REPLACE_EXISTING);
db.updateImageOf(id, strgReg.getPath(), table_children.name);
} catch (SQLException e) {
e.printStackTrace();
DialogUtils.displayError("Error saving child data", "There was an error in saving all child data. Please try again!");
return -1;
} catch (IOException e) {
e.printStackTrace();
DialogUtils.displayError("Error saving image", "There was an error saving the image of the child. " +
"All other data besides the image has been saved. Please attempt to add the child image in its own page.");
return -1;
}
refreshList();
if (active) {
firstNameInput.getScene().getWindow().hide();
}
return id;
}
private boolean formIsIncomplete() {
//Clear warning labels
warnEmptyLabel.setStyle("-fx-text-fill: transparent");
//Indicates that form is incomplete
boolean incomplete = false;
//Fetches textfield nodes from root
try {
List<Node> textFields = NodeUtils.getAllNodesOf(childImage.getParent(), new ArrayList<>(),
"javafx.scene.control.TextInputControl");
//Go mark each incomplete form
for (Node n : textFields) {
TextInputControl text = ((TextInputControl) n);
String[] ids;
if (text.getId() == null) {
ids = new String[] {"birthDateWarning", "admissionDateWarning"};
} else {
ids = new String[] {text.getId().replace("Input", "Warning")};
}
//Manipulate warning label if current node is NOT nickname textfield
if (!ids[0].contains("nick")) {
for (int i = 0; i < ids.length; i++) {
Label warning = ((Label) childImage.getParent().lookup("#" + ids[i]));
if (text.getText().isEmpty()) {
warning.setStyle("-fx-text-fill: red");
incomplete = true;
} else {
warning.setStyle("-fx-text-fill: transparent ");
}
}
}
}
//Notify user that form is incomplete
if (incomplete) warnEmptyLabel.setStyle("-fx-text-fill: red");
} catch (ClassNotFoundException e) {
e.printStackTrace();
DialogUtils.displayExceptionError(e, "An error has occurred! Please contact the developer for assistance!");
}
return incomplete;
}
#FXML
public void changeChildImg(ActionEvent actionEvent) {
FileChooser chooser = new FileChooser();
File chosen = chooser.showOpenDialog(firstNameInput.getScene().getWindow());
if (chosen == null) return;
try {
updateChosenImage(chosen);
} catch (IOException e) {
DialogUtils.displayError("File error", "There was an error selecting your chosen file, please try again");
e.printStackTrace();
}
}
private void updateChosenImage(File chosen) throws FileNotFoundException {
slctdImgStrm = new FileInputStream(chosen);
childImage.setImage(new Image(slctdImgStrm));
imageName.setText(chosen.getName());
pathRef = GlobalInfo.getChildrenImgDir() + "\\"+ chosen.getName();
slctdImgStrm = new FileInputStream(chosen);
}
private void refreshList() {
try {
listController.initTable();
} catch (SQLException e) {
DialogUtils.displayError("Synchronization error!", "There was an error synchronizing the data of the new child!");
e.printStackTrace();
}
}
public void setNextParent(Parent nextParent) {
this.nextParent = nextParent;
}
public void setListController(ListController listController) {
this.listController = listController;
}
Does anybody have any idea on what's causing this problem? Any searches on SO yield questions about fading the stage in and out which is not what I want.

Having trouble retrieving value from tableview

I'm having having trouble getting a correct output from tableview. I'm using a button to set one item from tableview to a label. However, it prints "StringProperty [Value pineapples]" where I would like it to be just "pineapples".
The tableview gives them correctly.
public class ProductListController implements Initializable {
#FXML public TableView<Model> tableview ;
#FXML private TableColumn<Model, Number> ProductID;
#FXML private TableColumn<Model, String> ProductName;
#FXML private TableColumn<Model, Number> ProductPrice;
#FXML private Label lblProduct;
#FXML private Label lblPrice;
#FXML
private void btnActionShow(ActionEvent event) {
assert tableview !=null : " ";
ProductID.setCellValueFactory(cellData -> cellData.getValue().ProductIDProperty());
ProductName.setCellValueFactory(cellData -> cellData.getValue().ProductNameProperty());
ProductPrice.setCellValueFactory(cellData -> cellData.getValue().ProductPriceProperty());
buildData();
}
private ObservableList<Model> data;
public void buildData(){
data = FXCollections.observableArrayList();
try{
Connection conn = DriverManager.getConnection
("jdbc:derby://localhost:1527/Stock", "*****", "*****");
Statement stmt = conn.createStatement();
String SQL = "SELECT * FROM PRODUCTS";
ResultSet rs = stmt.executeQuery(SQL);
while (rs.next()) {
Model mod = new Model();
mod.ProductID.set(rs.getInt("ID"));
mod.ProductName.set(rs.getString("NAME"));
mod.ProductPrice.set(rs.getInt("SELL_PRICE"));
data.add(mod);
}
tableview.setItems(data);
}
catch ( SQLException err) {
System.out.println(err.getMessage() );
}
}
//Button to fetch data from Tableview. Sets the data not the way I want.
#FXML
private void btnConfirmAction(ActionEvent event) {
Model model = tableview.getSelectionModel().getSelectedItem();
String prd;
prd = model.getProductName().toString();
lblProduct.setText(prd);
}
#FXML
private void btnNextAction(ActionEvent event) {
try{
FXMLLoader loader = new FXMLLoader(getClass().getResource("/appl/Discount.fxml"));
Parent parent = loader.load();
DiscountController discountcontr = loader.getController();
discountcontr.setProduct(tableview.getSelectionModel().getSelectedItem().getProductName().toString());
Stage stage = new Stage();
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.show();
}
catch(IOException e){
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
}
Model
public class Model {
public SimpleIntegerProperty ProductID = new SimpleIntegerProperty();
public SimpleStringProperty ProductName = new SimpleStringProperty ();
public SimpleIntegerProperty ProductPrice = new SimpleIntegerProperty();
private final SimpleBooleanProperty Checked = new SimpleBooleanProperty(false);
public SimpleBooleanProperty checkedProperty() {
return this.Checked;
}
public java.lang.Boolean getChecked() {
return this.checkedProperty().get();
}
public void setChecked(final java.lang.Boolean checked) {
this.checkedProperty().set(checked);
}
public SimpleIntegerProperty getProductID() {
return ProductID;
}
public SimpleStringProperty getProductName() {
return ProductName;
}
public SimpleIntegerProperty getProductPrice() {
return ProductPrice;
}
Since getProductName() returns a SimpleStringProperty, you need to retrieve the String from it using the get(). Just use :
String prd = model.getProductName().get();
Your model is implemented incorrectly. You should use the following pattern:
public class Model {
private SimpleStringProperty productName = new SimpleStringProperty();
public SimpleStringProperty productNameProperty() {
return productName ;
}
public final String getProductName() {
return productNameProperty().get();
}
public final void setProductName(String productName) {
productNameProperty().set(productName);
}
}
and similarly for the other properties.
If you use the e(fx)clipse plugin, you can generate the methods automatically from the property definition by right-clicking, choosing "Source" and then "Generate JavaFX Getters and Setters". I think NetBeans has similar functionality.

Resources