从理论上讲,您可以通过创建列表extractor来监控可观察列表中的项目以进行更改。这个想法是,对于TableView,您可以指定一个Callback,它为列表中的每个对象提供一个Observables数组。观察对象将在列表中进行观察,并且在现有项目对指定属性进行更改时,将通知任何与该列表一起注册的ListChangeListeners(通过wasUpdated()的更改返回true)。
但是,这似乎只适用于Java 8; JavaFX 2.2可能会存在一个bug。
下面是一个基于通常的TableView示例的示例。
import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableUpdatePropertyExample extends Application {
@Override
public void start(Stage primaryStage) {
final TableView<Person> table = new TableView<>();
table.setEditable(true);
final TableColumn<Person, String> firstNameCol = createTableColumn("First Name");
final TableColumn<Person, String> lastNameCol = createTableColumn("Last Name");
final TableColumn<Person, String> emailCol = createTableColumn("Email");
table.getColumns().addAll(Arrays.asList(firstNameCol, lastNameCol, emailCol));
final List<Person> data = Arrays.asList(
new Person("Jacob", "Smith", "[email protected]"),
new Person("Isabella", "Johnson", "[email protected]"),
new Person("Ethan", "Williams", "[email protected]"),
new Person("Emma", "Jones", "[email protected]"),
new Person("Michael", "Brown", "[email protected]")
);
table.setItems(FXCollections.observableList(data, new Callback<Person, Observable[]>() {
@Override
public Observable[] call(Person person) {
return new Observable[] {person.firstNameProperty(), person.lastNameProperty(), person.emailProperty()};
}
}));
table.getItems().addListener(new ListChangeListener<Person>() {
@Override
public void onChanged(
javafx.collections.ListChangeListener.Change<? extends Person> change) {
while (change.next()) {
if (change.wasUpdated()) {
Person updatedPerson = table.getItems().get(change.getFrom());
System.out.println(updatedPerson+" was updated");
}
}
}
});
final BorderPane root = new BorderPane();
root.setCenter(table);
final Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableColumn<Person, String> createTableColumn(String title) {
TableColumn<Person, String> col = new TableColumn<>(title);
col.setCellValueFactory(new PropertyValueFactory<Person, String>(makePropertyName(title)));
col.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
return col ;
}
private String makePropertyName(String text) {
boolean first = true ;
StringBuilder prop = new StringBuilder();
for (String word : text.split("\\s")) {
if (first) {
prop.append(word.toLowerCase());
} else {
prop.append(Character.toUpperCase(word.charAt(0)));
if (word.length() > 1) {
prop.append(word.substring(1));
}
}
first=false ;
}
return prop.toString();
}
public static class Person {
private final StringProperty firstName ;
private final StringProperty lastName ;
private final StringProperty email ;
public Person(String firstName, String lastName, String email) {
this.firstName = new SimpleStringProperty(this, "firstName", firstName);
this.lastName = new SimpleStringProperty(this, "lastName", lastName);
this.email = new SimpleStringProperty(this, "email", email);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public StringProperty firstNameProperty() {
return firstName ;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public StringProperty lastNameProperty() {
return lastName ;
}
public String getEmail() {
return email.get();
}
public void setEmail(String email) {
this.email.set(email);
}
public StringProperty emailProperty() {
return email ;
}
@Override
public String toString() {
return getFirstName() + " " + getLastName();
}
}
public static void main(String[] args) {
launch(args);
}
}
对于验证,您可能会考虑覆盖模型类属性中的set和setValue方法。我没有试过,我怀疑为了使其正常工作,您可能需要与TableCell的一塌糊涂,但是沿着线的东西:
this.email = new StringPropertyBase(email) {
final Pattern pattern = Pattern.compile("[a-zA-Z_0-9][email protected][a-zA-Z0-9.]+");
@Override
public String getName() {
return "email";
}
@Override
public Object getBean() {
return Person.this;
}
@Override
public void set(String email) {
if (pattern.matcher(email).matches()) {
super.set(email);
}
}
@Override
public void setValue(String email) {
if (pattern.matcher(email).matches()) {
super.setValue(email);
}
}
};
到位的一个衬垫的Person类以上。
更新: 为了使这个工作在JavaFX 2.2,你基本上可以推出你自己的版本的“提取器”。这是一个工作,但不是太糟糕。像下面的东西似乎工作,例如:
final List<Person> data = Arrays.asList(
new Person("Jacob", "Smith", "[email protected]"),
new Person("Isabella", "Johnson", "[email protected]"),
new Person("Ethan", "Williams", "[email protected]"),
new Person("Emma", "Jones", "[email protected]"),
new Person("Michael", "Brown", "[email protected]")
);
final ChangeListener<String> firstNameListener = new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> obs,
String oldFirstName, String newFirstName) {
Person person = (Person)((StringProperty)obs).getBean();
System.out.println("First name for "+person+" changed from "+oldFirstName+" to "+newFirstName);
}
};
final ChangeListener<String> lastNameListener = new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> obs,
String oldLastName, String newLastName) {
Person person = (Person)((StringProperty)obs).getBean();
System.out.println("Last name for "+person+" changed from "+oldLastName+" to "+oldLastName);
}
};
final ChangeListener<String> emailListener = new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> obs,
String oldEmail, String newEmail) {
Person person = (Person)((StringProperty)obs).getBean();
System.out.println("Email for "+person+" changed from "+oldEmail+" to "+oldEmail);
}
};
table.getItems().addListener(new ListChangeListener<Person>() {
@Override
public void onChanged(
javafx.collections.ListChangeListener.Change<? extends Person> change) {
while (change.next()) {
for (Person person : change.getAddedSubList()) {
person.firstNameProperty().addListener(
firstNameListener);
person.lastNameProperty().addListener(lastNameListener);
person.emailProperty().addListener(emailListener);
}
for (Person person : change.getRemoved()) {
person.firstNameProperty().removeListener(
firstNameListener);
person.lastNameProperty().removeListener(
lastNameListener);
person.emailProperty().removeListener(emailListener);
}
}
}
});
table.getItems().addAll(data);
(希望有帮助,顺便说一下,我可能错过了你的问题的重点......) –
感谢您花时间修改示例以说明您所描述的内容。我曾尝试过类似的东西,它并不像我在JavaFX 2.2中所称的onChanged方法那样。我不确定该方法的意图是什么。我在调试器中运行了这段代码,但没有看到它到达那里。 Oracle文档的帮助有限,因为它没有详细介绍此功能。我们计划迁移到JavaFX 8,但可能来不及帮助解决这个问题。 – kithril