-2

I am creating an application in JavaFX with an FXML file. The application will have a listview that takes in a person object class for firstName, lastName, and notes for personalHobbies. All with getters and setter. And a to string to with all the relevant items. Each class part is typed in a textField in the app by the user in the person list. And when a person is selected, all of the parts in the toString of each person class show like this: John Smith Hobbies include video games, playing, and writing.

The app also includes a button to add and delete a person from the list too. The problem is that all of the to string information shows up on the selection in the list, not just the first name by itself. I have been using an observable arraylist And everythibg but that works. This is my first post, and I am new to JavaFX so please forgive me, but I need help, thanks in advance.

Controller class with Person class

import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

public class ListViewWithTextAreaController implements Initializable{

@FXML
private TextArea textArea;

@FXML
private ListView<Person> listView;

@FXML
private TextField firstName;

@FXML
private TextField lastName;

@FXML
private TextArea personalHobbies;

//Key Component: ObservableList with variety of string item types for list.
final ObservableList<Person> listPerson = FXCollections.observableArrayList();


@FXML
void addButtonClicked(ActionEvent event) {
    //adds new item from the user to the list.

    Person newPerson = new Person(firstName.getText());
    newPerson.setLastName(lastName.getText());
    newPerson.setPersonalHobbies(personalHobbies.getText());

    listPerson.add(newPerson);

    String about = newPerson.toString();

    //shows the currently added Person to the TextField.
    textArea.setText(about);
    clearTextRefocus();

}

@FXML
void deleteButtonClicked(ActionEvent event){
    //Deletes the currently selected Person from the list.
    Person selectionToRemove = listView.getSelectionModel().getSelectedItem();
    listPerson.remove(selectionToRemove);

    textArea.clear();
    clearTextRefocus();

}

@Override
public void initialize(URL url, ResourceBundle rb){

    //Set the listed observableList items to the listView as selections.
    listView.setItems(listPerson);

        //ChangeListener for TextField to update for changes in focus on List items.
    listView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Person>() {
        @Override
        public void changed(ObservableValue<? extends Person> observable, Person oldValue, Person newValue) {
      if(listView.isFocused()){
          textArea.setText(newValue.toString());
          //textArea.getText();
      }
   }
   });    

    //Gets the selection of the first index model type in the listView,     then
    //Wrap the requestFocus inside a Platform.runLater() to set the focus
    //on the first element of the string index of zero "Add/Delete items Here".
    listView.getSelectionModel().select(0);

    Platform.runLater(new Runnable(){
        @Override
        public void run(){
            listView.requestFocus();
        }
    });
}

//Person  class.
private static class Person {

private String firstName;
private String lastName;
private String personalHobbies;

public Person(String firstName) {
    this.firstName = firstName;
    this.lastName = lastName = "";
    this.personalHobbies = "";
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getPersonalHobbies() {
    return personalHobbies;
}

public void setPersonalHobbies(String personalHobbies) {
    this.personalHobbies = personalHobbies;
}

@Override
public String toString() {
    return String.format("firstName " + firstName + "\nlastName " +   lastName 
            + "\n\tpersonal Hobbies " + personalHobbies);     

    }
}
public void clearTextRefocus(){
    //Auto clear the user Typing textFields.
    firstName.clear();
    lastName.clear();
    personalHobbies.clear();

    listView.requestFocus(); //Place focus back on the list (stops focus glitch).
}

}

All of the toString as the selection name

Johnny Taylor
  • 11
  • 1
  • 4
  • This post is useless without a code sample. – David Hempy Apr 24 '18 at 20:01
  • https://stackoverflow.com/questions/50008235/java-fx-simple-gui-edit-object-attributes-from-listview-how-to-access-objects – SedJ601 Apr 24 '18 at 20:08
  • Use a [cell factory](https://stackoverflow.com/questions/36657299/how-can-i-populate-a-listview-in-javafx-using-custom-objects) – James_D Apr 24 '18 at 22:23
  • @James_D Thank you for the cell factory suggestion, I didn't see this post. So I will research cell factory and learn how to use them. – Johnny Taylor Apr 25 '18 at 01:52
  • Possible duplicate of [How can I Populate a ListView in JavaFX using Custom Objects?](https://stackoverflow.com/questions/36657299/how-can-i-populate-a-listview-in-javafx-using-custom-objects) – kleopatra Apr 25 '18 at 08:00

1 Answers1

1

I was also able to figure out how to get it to work but this was the incorrect way by changing the to string to a getMethod and by creating a string to pass as a setText value to the textArea in the change listener of the initialize method. and changing the constructor of the Person class itself. A CellFactory was needed in this case with a change listener as suggested by James_D and kleopatra. I am placing the correct code and the wrong code as to show others like myself how to correctly accomplish this, and what not to do.

Here is the Correct Way with a cellFactory and change listener:

cellFactory correct way

import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

public class ListViewWithTextAreaController implements Initializable{

//Key Component: ObservableList with variety of string item types for list.
final ObservableList<Person> listPerson =  FXCollections.observableArrayList();

@FXML
private TextArea textArea;

@FXML
private ListView<Person> listView;

@FXML
private TextField firstName;

@FXML
private TextField lastName;

@FXML
private TextArea personalHobbies;


@FXML
void addButtonClicked(ActionEvent event) {
    //adds new item from the user to the list.

    Person newPerson = new Person(firstName.getText(), lastName.getText(),personalHobbies.getText());

    listPerson.add(newPerson);

    //shows the currently added Person to the TextField.
    textArea.setText(newPerson.toString());
    clearTextRefocus();

}

@FXML
void deleteButtonClicked(ActionEvent event){
    //Deletes the currently selected Person from the list.
    Person selectionToRemove = listView.getSelectionModel().getSelectedItem();
    listPerson.remove(selectionToRemove);

    textArea.clear();
    clearTextRefocus();

}

@Override
public void initialize(URL url, ResourceBundle rb){

    //Set the listed observableList items to the listView as selections.
    listPerson.add(new Person("Sam", "Hill", "Spelunking and exploring caves."));
    listPerson.add(new Person("Jane", "Plane", "Reading Books and sewing."));
    listPerson.add(new Person("Bernice", "Ternice", " Things and stuff."));
    listView.setItems(listPerson);


    //cell factory implemented.
    listView.setCellFactory(param -> new ListCell<Person>() {
        @Override
        protected void updateItem(Person p, boolean empty){
        super.updateItem(p, empty);
            if(empty || p == null || p.getFirstName() == null){
                setText("");
            }
            else{
                setText(p.getFirstName());
                //Change listener implemented.
                listView.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends Person> observable, Person oldValue, Person newValue) -> {
        if(listView.isFocused()){
            textArea.setText(newValue.toString());
        }
    });    
            }

        }
    });

    Platform.runLater(new Runnable(){
        @Override
        public void run(){
            listView.requestFocus();
        }
    });
}

public void clearTextRefocus(){
    //Auto clear the user Typing textFields.
    firstName.clear();
    lastName.clear();
    personalHobbies.clear();

    listView.requestFocus(); //Place focus back on the list (stops focus glitch).
}

    //Person  class.
private static class Person {

private String firstName;
private String lastName;
private String personalHobbies;

public Person(String firstName, String lastName, String hobbies) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.personalHobbies = hobbies;
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getPersonalHobbies() {
    return personalHobbies;
}

public void setPersonalHobbies(String personalHobbies) {
    this.personalHobbies = personalHobbies;
}

@Override
public String toString() {
    return String.format(getFirstName() + "\n" + getLastName() + "\n\t" + getPersonalHobbies());     

    }
}

}

Here is the wrong code and image:

incorrect listView Image

package listviewwithtextarea;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

public class ListViewWithTextAreaController implements Initializable{

@FXML
private TextArea textArea;

@FXML
private ListView<Person> listView;

@FXML
private TextField firstName;

@FXML
private TextField lastName;

@FXML
private TextArea personalHobbies;

//Key Component: ObservableList with variety of string item types for list.
final ObservableList<Person> listPerson = FXCollections.observableArrayList();  

@FXML
void addButtonClicked(ActionEvent event) {
    //adds new item from the user to the list.

    Person newPerson = new Person(firstName.getText(), lastName.getText(),personalHobbies.getText());

    listPerson.add(newPerson);

    //shows the currently added Person to the TextField.
    textArea.setText(newPerson.toString());
    clearTextRefocus();

}

@FXML
void deleteButtonClicked(ActionEvent event){
    //Deletes the currently selected Person from the list.
    Person selectionToRemove = listView.getSelectionModel().getSelectedItem();
    listPerson.remove(selectionToRemove);

    textArea.clear();
    clearTextRefocus();

}

@Override
public void initialize(URL url, ResourceBundle rb){

    //Set the listed observableList items to the listView as selections.
    listPerson.add(new Person("Sam", "Hill", "Spelunking and exploring caves."));
    listPerson.add(new Person("Jane", "Plane", "Reading Books and sewing."));
    listPerson.add(new Person("Bernice", "Ternice", " Things and stuff."));
    listView.setItems(listPerson);

        //ChangeListener for TextField to update for changes in focus on List items.
    listView.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends Person> observable, Person oldValue, Person newValue) -> {
        if(listView.isFocused()){
            String info = String.format(newValue.getFirstName() + "\n" +
                    newValue.getLastName() + "\n\t" + newValue.getPersonalHobbies());
            textArea.setText(info);
        }
    });    

    //Gets the selection of the first index model type in the listView, then
    //Wrap the requestFocus inside a Platform.runLater() to set the focus
    //on the first element of the string index of zero "Add/Delete items Here".
    listView.getSelectionModel().select(0);

    Platform.runLater(new Runnable(){
        @Override
        public void run(){
            listView.requestFocus();
        }
    });
}

public void clearTextRefocus(){
    //Auto clear the user Typing textFields.
    firstName.clear();
    lastName.clear();
    personalHobbies.clear();

    listView.requestFocus(); //Place focus back on the list (stops focus glitch).
}

    //Person  class.
private static class Person {

private String firstName;
private String lastName;
private String personalHobbies;

public Person(String firstName, String lastName, String hobbies) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.personalHobbies = hobbies;
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}`enter code here`

public String getPersonalHobbies() {
    return personalHobbies;
}

public void setPersonalHobbies(String personalHobbies) {
    this.personalHobbies = personalHobbies;
}

@Override
public String toString() {
    return getFirstName();     

    }
}

}

Johnny Taylor
  • 11
  • 1
  • 4
  • wrong approach - never-ever override toString for application reasons (what would you do if you want to show the lastname in another control?). A cellFactory is the only correct approach and it is certainly needed. – kleopatra Apr 25 '18 at 07:55
  • @kleopatra You are 100% correct this was the wrong approach to this. After researching cellFactory as suggested by James_D, I rewrote the code to reflect these changes and will Append them to the post. Sorry for the newbie error, but thank you guys. I am open to learning the correct way to code suggestions. – Johnny Taylor Apr 26 '18 at 15:42
  • cool :) Another quirk: the listener registration inside the factory (you add one on each call to updateItem which happens often). Not sure what you want to achieve, but whatever it is the factory is not the right place for it. – kleopatra Apr 27 '18 at 07:30