如何将 Date 类型属性绑定/取消绑定到 DatePicker 对象
how to bind/ unbind a Date type attribute to a DatePicker object
我有以下代码:
@FXML
private DatePicker birthday;
//other code
private final ChangeListener<Person> personListener = (value, oldValue, newValue) -> {
//other code
birthday.valueProperty().unbindBidirectional(oldValue.getBirthday());
//other code
};
生日 属性 属于 java.time.LocalDate 类型,属于 class 人。因为我使用 JPA,所以我不想使用 JavaFX 属性。
上面的代码无法编译。编译器的错误信息是:
error: no suitable method found for unbindBidirectional(LocalDate)
birthDayPicker.valueProperty().unbindBidirectional(oldV.getBirthday());
method Property.unbindBidirectional(Property<LocalDate>) is not applicable
(argument mismatch; LocalDate cannot be converted to Property<LocalDate>)
method ObjectProperty.unbindBidirectional(Property<LocalDate>) is not applicable
(argument mismatch; LocalDate cannot be converted to Property<LocalDate>)
我该如何解决这个问题?
更新:
我的人 class 有以下代码:
@Entity
@Table(name = "PERSON")
@NamedQueries({
@NamedQuery(name = "Person.findAll", query = "SELECT p FROM Person p"),
@NamedQuery(name = "Person.findById", query = "SELECT p FROM Person p WHERE p.id = :id"),
@NamedQuery(name = "Person.findByFirstname", query = "SELECT p FROM Person p WHERE p.firstname = :firstname"),
@NamedQuery(name = "Person.findByLastname", query = "SELECT p FROM Person p WHERE p.lastname = :lastname"),
@NamedQuery(name = "Person.findByMail", query = "SELECT p FROM Person p WHERE p.mail = :mail"),
@NamedQuery(name = "Person.findByBirthday", query = "SELECT p FROM Person p WHERE p.birthday = :birthday")})
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "ID")
private Integer id;
@Basic(optional = false)
@Column(name = "FIRSTNAME")
private String firstname;
@Column(name = "LASTNAME")
private String lastname;
@Column(name = "MAIL")
private String mail;
@Column(name = "BIRTHDAY")
@Temporal(TemporalType.DATE)
private LocalDate birthday;
public Person() {
}
public Person(Integer id) {
this.id = id;
}
public Person(Integer id, String firstname) {
this.id = id;
this.firstname = firstname;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
Integer oldId = this.id;
this.id = id;
listenerList.firePropertyChange("id", oldId, id);
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
String oldFirstName = this.firstname;
this.firstname = firstname;
listenerList.firePropertyChange("firstname", oldFirstName, firstname);
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
String oldLastName = this.lastname;
this.lastname = lastname;
listenerList.firePropertyChange("mail", oldLastName, lastname);
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
String oldMail = this.mail;
this.mail = mail;
listenerList.firePropertyChange("mail", oldMail, mail);
}
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
LocalDate oldBirthDay = this.birthday;
this.birthday = birthday;
listenerList.firePropertyChange("birthday", id, birthday);
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Person)) {
return false;
}
Person other = (Person) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "jpa.entities.Person[ id=" + id + " ]";
}
@Transient
final private PropertyChangeSupport listenerList = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
listenerList.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
listenerList.removePropertyChangeListener(listener);
}
}
控制器class:
public class PersonController implements Initializable {
@FXML
private TableView<Person> personsTable;
@FXML
private TableColumn<Person, Integer> idColumn;
@FXML
private TableColumn<Person, String> firstColumn;
@FXML
private TableColumn<Person, String> lastColumn;
@FXML
private TableColumn<Person, LocalDate> birthdayColumn;
@FXML
private TableColumn<Person, String> mailColumn;
@FXML
private TextField id;
@FXML
private TextField firstName;
@FXML
private TextField lastName;
@FXML
private TextField mail;
@FXML
private DatePicker birthDayPicker;
private EntityManagerFactory emf;
private EntityManager em;
private ObservableList<Person> data;
private LocalDate birthday;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
emf = Persistence.createEntityManagerFactory("persistenceTest");
em = emf.createEntityManager();
data = FXCollections.observableArrayList();
birthDayPicker.setOnAction((ActionEvent evnt) -> {
birthday = birthDayPicker.getValue();
});
personsTable.getSelectionModel().selectedItemProperty().addListener(personListener);
configureColumn();
populate();
}
@FXML
private void addPerson(ActionEvent event) {
em.getTransaction().begin();
Person p = new Person(Integer.parseInt(id.getText()), firstName.getText());
p.setLastname(lastName.getText());
p.setBirthday(birthDayPicker.getValue());
p.setMail(mail.getText());
em.persist(p);
data.add(p);
em.getTransaction().commit();
}
@FXML
private void savePerson(ActionEvent event) {
}
@FXML
private void deletePerson(ActionEvent event) {
em.getTransaction().begin();
Person p = personsTable.getSelectionModel().selectedItemProperty().getValue();
data.remove(p);
em.remove(p);
em.getTransaction().commit();
}
private void populate() {
TypedQuery<Person> query = em.createQuery(
"SELECT e FROM Person e", jpa.entities.Person.class);
List<Person> list = query.getResultList();
data.addAll(list);
personsTable.setItems(data);
}
private void configureColumn() {
idColumn.setCellValueFactory(new PropertyValueFactory<Person, Integer>("id"));
firstColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("firstname"));
lastColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("lastname"));
birthdayColumn.setCellValueFactory(new PropertyValueFactory<Person, LocalDate>("birthday"));
birthdayColumn.setCellFactory(p -> {
return new TableCell<Person, LocalDate>() {
@Override
protected void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
final DateTimeFormatter format = DateTimeFormatter.ofPattern("dd/MM/yyyy");
setText(item.format(format));
}
}
};
});
mailColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("mail"));
}
private final ChangeListener<Person> personListener = (value, oldV, newV) -> {
if (oldV != null) {
id.textProperty().unbindBidirectional(oldV.getId());
firstName.textProperty().unbindBidirectional(oldV.getFirstname());
lastName.textProperty().unbindBidirectional(oldV.getLastname());
birthDayPicker.valueProperty().unbindBidirectional(oldV.getBirthday()); // error
mail.textProperty().unbindBidirectional(oldV.getMail());
}
if (newV != null) {
try {
id.textProperty().bindBidirectional(JavaBeanIntegerPropertyBuilder.create().bean(newV).name("id").build(), new NumberStringConverter());
firstName.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("firstname").build());
lastName.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("lastname").build());
birthDayPicker.valueProperty().bindBidirectional(); // error
mail.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("mail").build());
} catch (NoSuchMethodException e) {
System.out.println("erreur : " + e.getMessage());
}
}
};
}
更改 Person 中的日期类型 class,然后添加并使用适当的访问器。
public class Person {
final private ObjectProperty<LocalDate> birthday;
public Person(LocalDate birthday) {
this.birthday = new SimpleObjectProperty<LocalDate>(birthday);
}
public LocalDate getBirthday() {
return birthday.get();
}
public void setBirthday(LocalDate birthday) {
this.birthday.set(birthday);
}
public ObjectProperty<LocalDate> birthdayProperty() {
return birthday;
}
}
. . .
@FXML
private DatePicker birthday;
//other code
private final ChangeListener<Person> personListener = (value, oldValue, newValue) -> {
//other code
birthday.valueProperty().unbindBidirectional(oldValue.birthdayProperty());
//other code
};
最简单的方法就是在 Person
class 中使用 JavaFX 属性。只要您使用 "property access" 而不是 "field access",这就适用于 JPA。即:
public class Person {
private final StringProperty firstname = new SimpleStringProperty();
public StringProperty firstnameProperty() {
return firstname ;
}
@Basic(optional = false)
@Column(name = "FIRSTNAME")
public final String getFirstname() {
return firstnameProperty().get();
}
public final void setFirstname(String firstname) {
firstnameProperty().set(firstname);
}
private final ObjectProperty<LocalDate> birthday = new SimpleObjectProperty<>();
public ObjectProperty<LocalDate> birthdayProperty() {
return birthday ;
}
@Column(name="BIRTHDAY")
@Temporal(TemporalType.DATE)
public LocalDate getBirthday() {
return birthdayProperty().get();
}
public void setBirthday(LocalDate birthday) {
birthdayProperty().set(birthday);
}
// etc
}
(请注意,Hibernate 仍然反对 final
get
和 set
方法,因此如果您使用 Hibernate,则必须将这些方法设置为非最终方法,这会稍微少一些比理想情况要差。如果您使用符合 JPA 的 ORM,这应该不会造成问题。)
如果您出于某种原因无法在您的实体中使用 JavaFX 属性,您可以使用 JavaBeanObjectProperty
管理绑定。以下几行代码应该可以工作:
public class PersonController {
private JavaBeanObjectProperty birthdayPropertyAdapter ;
// ...
private final ChangeListener<Person> personListener = (value, oldV, newV) -> {
if (oldV != null) {
id.textProperty().unbindBidirectional(oldV.getId());
firstName.textProperty().unbindBidirectional(oldV.getFirstname());
lastName.textProperty().unbindBidirectional(oldV.getLastname());
mail.textProperty().unbindBidirectional(oldV.getMail());
}
if (birthdayPropertyAdapter != null) {
birthdayPicker.valueProperty().unbindBidirectional(birthdayPropertyAdapter);
}
if (newV != null) {
try {
id.textProperty().bindBidirectional(JavaBeanIntegerPropertyBuilder.create().bean(newV).name("id").build(), new NumberStringConverter());
firstName.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("firstname").build());
lastName.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("lastname").build());
mail.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("mail").build());
birthdayPropertyAdapter = JavaBeanObjectPropertyBuilder.create()
.bean(newV)
.name("birthday")
.build();
birthdayPicker.valueProperty().bindBidirectional(birthdayPropertyAdapter);
} catch (NoSuchMethodException e) {
System.out.println("erreur : " + e.getMessage());
}
}
};
我有以下代码:
@FXML
private DatePicker birthday;
//other code
private final ChangeListener<Person> personListener = (value, oldValue, newValue) -> {
//other code
birthday.valueProperty().unbindBidirectional(oldValue.getBirthday());
//other code
};
生日 属性 属于 java.time.LocalDate 类型,属于 class 人。因为我使用 JPA,所以我不想使用 JavaFX 属性。 上面的代码无法编译。编译器的错误信息是:
error: no suitable method found for unbindBidirectional(LocalDate)
birthDayPicker.valueProperty().unbindBidirectional(oldV.getBirthday());
method Property.unbindBidirectional(Property<LocalDate>) is not applicable
(argument mismatch; LocalDate cannot be converted to Property<LocalDate>)
method ObjectProperty.unbindBidirectional(Property<LocalDate>) is not applicable
(argument mismatch; LocalDate cannot be converted to Property<LocalDate>)
我该如何解决这个问题?
更新: 我的人 class 有以下代码:
@Entity
@Table(name = "PERSON")
@NamedQueries({
@NamedQuery(name = "Person.findAll", query = "SELECT p FROM Person p"),
@NamedQuery(name = "Person.findById", query = "SELECT p FROM Person p WHERE p.id = :id"),
@NamedQuery(name = "Person.findByFirstname", query = "SELECT p FROM Person p WHERE p.firstname = :firstname"),
@NamedQuery(name = "Person.findByLastname", query = "SELECT p FROM Person p WHERE p.lastname = :lastname"),
@NamedQuery(name = "Person.findByMail", query = "SELECT p FROM Person p WHERE p.mail = :mail"),
@NamedQuery(name = "Person.findByBirthday", query = "SELECT p FROM Person p WHERE p.birthday = :birthday")})
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "ID")
private Integer id;
@Basic(optional = false)
@Column(name = "FIRSTNAME")
private String firstname;
@Column(name = "LASTNAME")
private String lastname;
@Column(name = "MAIL")
private String mail;
@Column(name = "BIRTHDAY")
@Temporal(TemporalType.DATE)
private LocalDate birthday;
public Person() {
}
public Person(Integer id) {
this.id = id;
}
public Person(Integer id, String firstname) {
this.id = id;
this.firstname = firstname;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
Integer oldId = this.id;
this.id = id;
listenerList.firePropertyChange("id", oldId, id);
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
String oldFirstName = this.firstname;
this.firstname = firstname;
listenerList.firePropertyChange("firstname", oldFirstName, firstname);
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
String oldLastName = this.lastname;
this.lastname = lastname;
listenerList.firePropertyChange("mail", oldLastName, lastname);
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
String oldMail = this.mail;
this.mail = mail;
listenerList.firePropertyChange("mail", oldMail, mail);
}
public LocalDate getBirthday() {
return birthday;
}
public void setBirthday(LocalDate birthday) {
LocalDate oldBirthDay = this.birthday;
this.birthday = birthday;
listenerList.firePropertyChange("birthday", id, birthday);
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Person)) {
return false;
}
Person other = (Person) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "jpa.entities.Person[ id=" + id + " ]";
}
@Transient
final private PropertyChangeSupport listenerList = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
listenerList.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
listenerList.removePropertyChangeListener(listener);
}
}
控制器class:
public class PersonController implements Initializable {
@FXML
private TableView<Person> personsTable;
@FXML
private TableColumn<Person, Integer> idColumn;
@FXML
private TableColumn<Person, String> firstColumn;
@FXML
private TableColumn<Person, String> lastColumn;
@FXML
private TableColumn<Person, LocalDate> birthdayColumn;
@FXML
private TableColumn<Person, String> mailColumn;
@FXML
private TextField id;
@FXML
private TextField firstName;
@FXML
private TextField lastName;
@FXML
private TextField mail;
@FXML
private DatePicker birthDayPicker;
private EntityManagerFactory emf;
private EntityManager em;
private ObservableList<Person> data;
private LocalDate birthday;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
emf = Persistence.createEntityManagerFactory("persistenceTest");
em = emf.createEntityManager();
data = FXCollections.observableArrayList();
birthDayPicker.setOnAction((ActionEvent evnt) -> {
birthday = birthDayPicker.getValue();
});
personsTable.getSelectionModel().selectedItemProperty().addListener(personListener);
configureColumn();
populate();
}
@FXML
private void addPerson(ActionEvent event) {
em.getTransaction().begin();
Person p = new Person(Integer.parseInt(id.getText()), firstName.getText());
p.setLastname(lastName.getText());
p.setBirthday(birthDayPicker.getValue());
p.setMail(mail.getText());
em.persist(p);
data.add(p);
em.getTransaction().commit();
}
@FXML
private void savePerson(ActionEvent event) {
}
@FXML
private void deletePerson(ActionEvent event) {
em.getTransaction().begin();
Person p = personsTable.getSelectionModel().selectedItemProperty().getValue();
data.remove(p);
em.remove(p);
em.getTransaction().commit();
}
private void populate() {
TypedQuery<Person> query = em.createQuery(
"SELECT e FROM Person e", jpa.entities.Person.class);
List<Person> list = query.getResultList();
data.addAll(list);
personsTable.setItems(data);
}
private void configureColumn() {
idColumn.setCellValueFactory(new PropertyValueFactory<Person, Integer>("id"));
firstColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("firstname"));
lastColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("lastname"));
birthdayColumn.setCellValueFactory(new PropertyValueFactory<Person, LocalDate>("birthday"));
birthdayColumn.setCellFactory(p -> {
return new TableCell<Person, LocalDate>() {
@Override
protected void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
} else {
final DateTimeFormatter format = DateTimeFormatter.ofPattern("dd/MM/yyyy");
setText(item.format(format));
}
}
};
});
mailColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("mail"));
}
private final ChangeListener<Person> personListener = (value, oldV, newV) -> {
if (oldV != null) {
id.textProperty().unbindBidirectional(oldV.getId());
firstName.textProperty().unbindBidirectional(oldV.getFirstname());
lastName.textProperty().unbindBidirectional(oldV.getLastname());
birthDayPicker.valueProperty().unbindBidirectional(oldV.getBirthday()); // error
mail.textProperty().unbindBidirectional(oldV.getMail());
}
if (newV != null) {
try {
id.textProperty().bindBidirectional(JavaBeanIntegerPropertyBuilder.create().bean(newV).name("id").build(), new NumberStringConverter());
firstName.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("firstname").build());
lastName.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("lastname").build());
birthDayPicker.valueProperty().bindBidirectional(); // error
mail.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("mail").build());
} catch (NoSuchMethodException e) {
System.out.println("erreur : " + e.getMessage());
}
}
};
}
更改 Person 中的日期类型 class,然后添加并使用适当的访问器。
public class Person {
final private ObjectProperty<LocalDate> birthday;
public Person(LocalDate birthday) {
this.birthday = new SimpleObjectProperty<LocalDate>(birthday);
}
public LocalDate getBirthday() {
return birthday.get();
}
public void setBirthday(LocalDate birthday) {
this.birthday.set(birthday);
}
public ObjectProperty<LocalDate> birthdayProperty() {
return birthday;
}
}
. . .
@FXML
private DatePicker birthday;
//other code
private final ChangeListener<Person> personListener = (value, oldValue, newValue) -> {
//other code
birthday.valueProperty().unbindBidirectional(oldValue.birthdayProperty());
//other code
};
最简单的方法就是在 Person
class 中使用 JavaFX 属性。只要您使用 "property access" 而不是 "field access",这就适用于 JPA。即:
public class Person {
private final StringProperty firstname = new SimpleStringProperty();
public StringProperty firstnameProperty() {
return firstname ;
}
@Basic(optional = false)
@Column(name = "FIRSTNAME")
public final String getFirstname() {
return firstnameProperty().get();
}
public final void setFirstname(String firstname) {
firstnameProperty().set(firstname);
}
private final ObjectProperty<LocalDate> birthday = new SimpleObjectProperty<>();
public ObjectProperty<LocalDate> birthdayProperty() {
return birthday ;
}
@Column(name="BIRTHDAY")
@Temporal(TemporalType.DATE)
public LocalDate getBirthday() {
return birthdayProperty().get();
}
public void setBirthday(LocalDate birthday) {
birthdayProperty().set(birthday);
}
// etc
}
(请注意,Hibernate 仍然反对 final
get
和 set
方法,因此如果您使用 Hibernate,则必须将这些方法设置为非最终方法,这会稍微少一些比理想情况要差。如果您使用符合 JPA 的 ORM,这应该不会造成问题。)
如果您出于某种原因无法在您的实体中使用 JavaFX 属性,您可以使用 JavaBeanObjectProperty
管理绑定。以下几行代码应该可以工作:
public class PersonController {
private JavaBeanObjectProperty birthdayPropertyAdapter ;
// ...
private final ChangeListener<Person> personListener = (value, oldV, newV) -> {
if (oldV != null) {
id.textProperty().unbindBidirectional(oldV.getId());
firstName.textProperty().unbindBidirectional(oldV.getFirstname());
lastName.textProperty().unbindBidirectional(oldV.getLastname());
mail.textProperty().unbindBidirectional(oldV.getMail());
}
if (birthdayPropertyAdapter != null) {
birthdayPicker.valueProperty().unbindBidirectional(birthdayPropertyAdapter);
}
if (newV != null) {
try {
id.textProperty().bindBidirectional(JavaBeanIntegerPropertyBuilder.create().bean(newV).name("id").build(), new NumberStringConverter());
firstName.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("firstname").build());
lastName.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("lastname").build());
mail.textProperty().bindBidirectional(JavaBeanStringPropertyBuilder.create().bean(newV).name("mail").build());
birthdayPropertyAdapter = JavaBeanObjectPropertyBuilder.create()
.bean(newV)
.name("birthday")
.build();
birthdayPicker.valueProperty().bindBidirectional(birthdayPropertyAdapter);
} catch (NoSuchMethodException e) {
System.out.println("erreur : " + e.getMessage());
}
}
};