对于第一个问题,最简单的方法是使用EasyBind 框架。那么就这么简单
ObservableList<String> stringList = EasyBind.map(myBaseList, myConverter::toString);
这是一个使用 EasyBind 的 SSCCE:
import org.fxmisc.easybind.EasyBind;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.util.StringConverter;
public class MappedAndTransformedListExample {
public static void main(String[] ags) {
ObservableList<Person> baseList = FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith@example.com"),
new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
new Person("Ethan", "Williams", "ethan.williams@example.com"),
new Person("Emma", "Jones", "emma.jones@example.com")
);
StringConverter<Person> converter = new StringConverter<Person>() {
@Override
public String toString(Person person) {
return person.getFirstName() + " " + person.getLastName();
}
@Override
public Person fromString(String string) {
int indexOfDelimiter = string.indexOf(' ');
return new Person(string.substring(0, indexOfDelimiter),
string.substring(indexOfDelimiter+1),
"");
}
};
ObservableList<String> namesList = EasyBind.map(baseList, converter::toString);
namesList.forEach(System.out::println);
namesList.addListener((Change<? extends String> c) -> {
while (c.next()) {
if (c.wasAdded()) {
System.out.println("Added "+c.getAddedSubList());
}
}
});
System.out.println("\nAdding Michael to base list...\n");
baseList.add(new Person("Michael", "Brown", "michael.brown@example.com"));
namesList.forEach(System.out::println);
}
public static class Person {
private final StringProperty firstName = new SimpleStringProperty(this, "firstName");
private final StringProperty lastName = new SimpleStringProperty(this, "lastName");
private final StringProperty email = new SimpleStringProperty(this, "email");
public Person(String firstName, String lastName, String email) {
this.firstName.set(firstName);
this.lastName.set(lastName);
this.email.set(email);
}
public final StringProperty firstNameProperty() {
return this.firstName;
}
public final String getFirstName() {
return this.firstNameProperty().get();
}
public final void setFirstName(final String firstName) {
this.firstNameProperty().set(firstName);
}
public final StringProperty lastNameProperty() {
return this.lastName;
}
public final java.lang.String getLastName() {
return this.lastNameProperty().get();
}
public final void setLastName(final java.lang.String lastName) {
this.lastNameProperty().set(lastName);
}
public final StringProperty emailProperty() {
return this.email;
}
public final java.lang.String getEmail() {
return this.emailProperty().get();
}
public final void setEmail(final java.lang.String email) {
this.emailProperty().set(email);
}
}
}
如果您出于某种原因不想使用第三方框架,您可以使用TransformationList(这是 EasyBind 在后台所做的:我从那里的源代码中复制了下面的代码并对其进行了修改)。
在上面,你会替换
ObservableList<String> namesList = EasyBind.map(baseList, converter::toString);
与
ObservableList<String> namesList = new TransformationList<String, Person>(baseList) {
@Override
public int getSourceIndex(int index) {
return index ;
}
@Override
public String get(int index) {
return converter.toString(getSource().get(index));
}
@Override
public int size() {
return getSource().size();
}
@Override
protected void sourceChanged(Change<? extends Person> c) {
fireChange(new Change<String>(this) {
@Override
public boolean wasAdded() {
return c.wasAdded();
}
@Override
public boolean wasRemoved() {
return c.wasRemoved();
}
@Override
public boolean wasReplaced() {
return c.wasReplaced();
}
@Override
public boolean wasUpdated() {
return c.wasUpdated();
}
@Override
public boolean wasPermutated() {
return c.wasPermutated();
}
@Override
public int getPermutation(int i) {
return c.getPermutation(i);
}
@Override
protected int[] getPermutation() {
// This method is only called by the superclass methods
// wasPermutated() and getPermutation(int), which are
// both overriden by this class. There is no other way
// this method can be called.
throw new AssertionError("Unreachable code");
}
@Override
public List<String> getRemoved() {
ArrayList<String> res = new ArrayList<>(c.getRemovedSize());
for(Person removedPerson: c.getRemoved()) {
res.add(converter.toString(removedPerson));
}
return res;
}
@Override
public int getFrom() {
return c.getFrom();
}
@Override
public int getTo() {
return c.getTo();
}
@Override
public boolean next() {
return c.next();
}
@Override
public void reset() {
c.reset();
}
});
}
};
对于第二个问题,您必须使用转换列表。这是一个更新的main(...) 方法,它显示了如何执行此操作。 (它同样适用于第 1 部分的第二个版本。)
public static void main(String[] ags) {
ObservableList<Person> baseList = FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith@example.com"),
new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
new Person("Ethan", "Williams", "ethan.williams@example.com"),
new Person("Emma", "Jones", "emma.jones@example.com")
);
StringConverter<Person> converter = new StringConverter<Person>() {
@Override
public String toString(Person person) {
return person.getFirstName() + " " + person.getLastName();
}
@Override
public Person fromString(String string) {
int indexOfDelimiter = string.indexOf(' ');
return new Person(string.substring(0, indexOfDelimiter),
string.substring(indexOfDelimiter+1),
"");
}
};
ObservableList<String> namesList = EasyBind.map(baseList, converter::toString);
ObservableList<String> namesListWithHeader = new TransformationList<String, String>(namesList) {
@Override
public int getSourceIndex(int index) {
return index - 1 ;
}
@Override
public String get(int index) {
if (index == 0) {
return "Contacts";
} else {
return getSource().get(index - 1);
}
}
@Override
public int size() {
return getSource().size() + 1 ;
}
@Override
protected void sourceChanged(Change<? extends String> c) {
fireChange(new Change<String>(this) {
@Override
public boolean wasAdded() {
return c.wasAdded();
}
@Override
public boolean wasRemoved() {
return c.wasRemoved();
}
@Override
public boolean wasReplaced() {
return c.wasReplaced();
}
@Override
public boolean wasUpdated() {
return c.wasUpdated();
}
@Override
public boolean wasPermutated() {
return c.wasPermutated();
}
@Override
public int getPermutation(int i) {
return c.getPermutation(i - 1) + 1;
}
@Override
protected int[] getPermutation() {
// This method is only called by the superclass methods
// wasPermutated() and getPermutation(int), which are
// both overriden by this class. There is no other way
// this method can be called.
throw new AssertionError("Unreachable code");
}
@Override
public List<String> getRemoved() {
ArrayList<String> res = new ArrayList<>(c.getRemovedSize());
for(String removed: c.getRemoved()) {
res.add(removed);
}
return res;
}
@Override
public int getFrom() {
return c.getFrom() + 1;
}
@Override
public int getTo() {
return c.getTo() + 1;
}
@Override
public boolean next() {
return c.next();
}
@Override
public void reset() {
c.reset();
}
});
}
};
namesListWithHeader.forEach(System.out::println);
namesListWithHeader.addListener((Change<? extends String> c) -> {
while (c.next()) {
if (c.wasAdded()) {
System.out.println("Added "+c.getAddedSubList());
System.out.println("From: "+c.getFrom()+", To: "+c.getTo());
}
}
});
System.out.println("\nAdding Michael to base list...\n");
baseList.add(new Person("Michael", "Brown", "michael.brown@example.com"));
namesListWithHeader.forEach(System.out::println);
}