JavaFx - How to display SimpleStringProperty value

2020-07-18 06:10发布

问题:

I am busy working through a tutorial and am stuck on one point.

Basically launch new scene and display values from ObservableList of type Person in a table view.

The person class consists of 3 SimpleStringProperty’s firsName, lastName and email.

But when I run the app it seems to display the values of the SimpleStringProperty [StringProperty [value:actualvalue]] in the table and not the value of the SimpleStringProperty. If I change the Person’s class getFirstName method to return a String firstName.get() then it display the value correctly in the table.

Am I supposed to use the SimpleStringProperty or rather plain objects like String?

The person class

package co.za.chrispie.addressBook;

import javafx.beans.property.SimpleStringProperty;

public class Person {

private SimpleStringProperty firstName;
private SimpleStringProperty lastName;
private SimpleStringProperty email;

public Person(final String firstName, final String lastName, final String email) {
    this.firstName = new SimpleStringProperty(firstName);
    this.lastName = new SimpleStringProperty(lastName);
    this.email = new SimpleStringProperty(email);
}

public String getFirstName() {
    return firstName.get(); //Changes this method to return a String
}

public SimpleStringProperty getLastName() {
    return lastName;
}

public SimpleStringProperty getEmail() {
    return email;
}

}

The Controller class

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package co.za.chrispie.addressBook;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;

public class OracleAddressBookController implements Initializable {

@FXML
TableView<Person> table;
@FXML
TableColumn<Person, String> colFirstName;
@FXML
TableColumn<Person, String> colLastName;
@FXML
TableColumn<Person, String> colEmail;

final ObservableList<Person> data = FXCollections.observableArrayList(
    new Person("Jaco", "Pieters", "jp@me.co.za"),
    new Person("Chrispie", "Pieters", "chrispie@me.co.za")
);

@Override
public void initialize(URL url, ResourceBundle rb) {
    assert colFirstName != null : "fx:id=\"colFirstName\" was not injected: check your FXML file 'OracleAddressBook.fxml'.";
    assert colLastName != null : "fx:id=\"colLastName\" was not injected: check your FXML file 'OracleAddressBook.fxml'.";
    assert colEmail != null : "fx:id=\"colEmail\" was not injected: check your FXML file 'OracleAddressBook.fxml'.";
    configureTable();
}    

private void configureTable() {
    colFirstName.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
    colLastName.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
    colEmail.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));

    table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

    table.setItems(data);
    assert table.getItems() == data;
}
}

and the front end FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="500.0" prefWidth="600.0"    styleClass="mainFxmlClass" xmlns:fx="http://javafx.com/fxml"  fx:controller="co.za.chrispie.addressBook.OracleAddressBookController">
<children>
  <Label layoutX="14.0" layoutY="11.0" text="Address Book" />
  <TableView fx:id="table" layoutX="14.0" layoutY="35.0" prefHeight="451.0" prefWidth="572.0">
  <columns>
    <TableColumn prefWidth="75.0" text="First Name" fx:id="colFirstName" />
    <TableColumn prefWidth="75.0" text="Last Name" fx:id="colLastName" />
    <TableColumn prefWidth="75.0" text="Email" fx:id="colEmail" />
  </columns>
</TableView>
 </children>
  <stylesheets>
   <URL value="@oracleaddressbook.css" />
 </stylesheets>
</AnchorPane>

回答1:

You need to change the name of your property getters to nameProperty(), where name is your property. So you would have firstNameProperty() and emailProperty().

getName() works, but the table won't observe the property's changes.

The doc for PropertyValueFactory explains this subject:

In this example, the "firstName" string is used as a reference to an assumed firstNameProperty() method in the Person class type (which is the class type of the TableView items list). Additionally, this method must return a Property instance. If a method meeting these requirements is found, then the TableCell is populated with this ObservableValue . In addition, the TableView will automatically add an observer to the returned value, such that any changes fired will be observed by the TableView, resulting in the cell immediately updating.

If no method matching this pattern exists, there is fall-through support for attempting to call get() or is() (that is, getFirstName() or isFirstName() in the example above). If a method matching this pattern exists, the value returned from this method is wrapped in a ReadOnlyObjectWrapper and returned to the TableCell. However, in this situation, this means that the TableCell will not be able to observe the ObservableValue for changes (as is the case in the first approach above).