JavaFX:为满足条件的 ObservableList 设置计数限制
JavaFX: Setting count limit for an ObservableList fulfilling a condition
我举个例子来说明。
public class Person
{
private final ObjectProperty<Gender> gender;
public final ObjectProperty<Gender> genderProperty()
{
return this.gender;
}
public final void setGender(Gender value)
{
this.genderProperty().set(value);
}
public final Gender getGender()
{
return this.genderProperty().get();
}
public static enum Gender { MALE, FEMALE }
/* Other properties */
}
其他地方...
public class MyClass
{
private final ObservableList<Person> people;
public final ObservableList<Person> getPeople()
{
return this.people;
}
public MyClass()
{
// Create observable arraylist with extractor
this.people = FXCollections.observableArrayList(
person -> new Observable[]
{
person.genderProperty()
}
);
}
}
我需要 people
列表最多包含 10 个男性和最多 5 个女性。某些Person
对象在添加到people
列表时没有gender
信息,但我的应用程序必须:
- 当其中一个
Person
对象更改其 gender
时,选择这样的更改,并且该更改恰好违反了此限制。
- 撤消这样的更改,这样我的 10 男/5 女限制规则将始终适用。
我能做些什么来确保这一点?
首先,您可以在 Gender
中添加一个代表未知性别的新枚举值:
public enum Gender { MALE, FEMALE, UNKNOWN }
.
然后你可以使用 ListChangeListener
比如:
this.people = FXCollections.observableArrayList(person -> new Observable[] {person.genderProperty()});
ListChangeListener<Person> listener = new ListChangeListener<Person>() {
private boolean checkCondition(ObservableList<Person> list, Person.Gender gender) {
int males = 0;
int females = 0;
for (Person person : list) {
switch (person.getGender()) {
case MALE: males++; break;
case FEMALE: females++; break;
default: break;
}
}
return ((males > 10 && gender == Person.Gender.MALE) ||
(females > 5 && gender == Person.Gender.FEMALE));
}
@Override
public void onChanged(Change<? extends Person> c) {
while (c.next()) {
if (c.wasAdded()) {
for (Person person : c.getAddedSubList()) {
if (checkCondition((ObservableList<Person>) c.getList(), person.getGender()))
c.getList().remove(person);
}
}
if (c.wasUpdated()) {
for (int update = c.getFrom(); update < c.getTo(); update++) {
Person person = c.getList().get(update);
if (checkCondition((ObservableList<Person>) c.getList(), person.getGender()))
person.setGender(Person.Gender.UNKNOWN);
}
}
}
}
};
people.addListener(listener);
此解决方案的唯一问题是,它实际上并没有 "revert" 更新更改,而是将性别设置为新的未知值。
如果你真的想恢复更改,解决方案可以是这样的:
this.people = FXCollections.observableArrayList();
ListChangeListener<Person> listener = new ListChangeListener<Person>() {
private boolean checkCondition(ObservableList<Person> list, Person.Gender gender) {
int males = 0;
int females = 0;
for (Person person : list) {
switch (person.getGender()) {
case MALE: males++; break;
case FEMALE: females++; break;
default: break;
}
}
return ((males > 10 && gender == Person.Gender.MALE) ||
(females > 5 && gender == Person.Gender.FEMALE));
}
@Override
public void onChanged(Change<? extends Person> c) {
while (c.next()) {
if (c.wasAdded()) {
for (Person person : c.getAddedSubList()) {
if (checkCondition((ObservableList<Person>) c.getList(), person.getGender()))
c.getList().remove(person);
else
person.genderProperty().addListener((obs, oldval, newval) -> {
if (checkCondition((ObservableList<Person>) c.getList(), newval))
person.setGender(oldval);
});
}
}
}
}
};
people.addListener(listener);
差异:提取器已被删除,因为在 ListChangeListener
内部仅包含元素的添加。当添加一个新元素时,其 genderProperty
上的侦听器已被添加,该侦听器检查性别更新,如果不满足条件,则该基因将恢复为原始基因。
您也可以通过不公开列表,而是公开操作列表的方法来实现相同的功能:addPersonAt
、removePersonAt
和 updateGenderAt
。
我举个例子来说明。
public class Person
{
private final ObjectProperty<Gender> gender;
public final ObjectProperty<Gender> genderProperty()
{
return this.gender;
}
public final void setGender(Gender value)
{
this.genderProperty().set(value);
}
public final Gender getGender()
{
return this.genderProperty().get();
}
public static enum Gender { MALE, FEMALE }
/* Other properties */
}
其他地方...
public class MyClass
{
private final ObservableList<Person> people;
public final ObservableList<Person> getPeople()
{
return this.people;
}
public MyClass()
{
// Create observable arraylist with extractor
this.people = FXCollections.observableArrayList(
person -> new Observable[]
{
person.genderProperty()
}
);
}
}
我需要 people
列表最多包含 10 个男性和最多 5 个女性。某些Person
对象在添加到people
列表时没有gender
信息,但我的应用程序必须:
- 当其中一个
Person
对象更改其gender
时,选择这样的更改,并且该更改恰好违反了此限制。 - 撤消这样的更改,这样我的 10 男/5 女限制规则将始终适用。
我能做些什么来确保这一点?
首先,您可以在 Gender
中添加一个代表未知性别的新枚举值:
public enum Gender { MALE, FEMALE, UNKNOWN }
.
然后你可以使用 ListChangeListener
比如:
this.people = FXCollections.observableArrayList(person -> new Observable[] {person.genderProperty()});
ListChangeListener<Person> listener = new ListChangeListener<Person>() {
private boolean checkCondition(ObservableList<Person> list, Person.Gender gender) {
int males = 0;
int females = 0;
for (Person person : list) {
switch (person.getGender()) {
case MALE: males++; break;
case FEMALE: females++; break;
default: break;
}
}
return ((males > 10 && gender == Person.Gender.MALE) ||
(females > 5 && gender == Person.Gender.FEMALE));
}
@Override
public void onChanged(Change<? extends Person> c) {
while (c.next()) {
if (c.wasAdded()) {
for (Person person : c.getAddedSubList()) {
if (checkCondition((ObservableList<Person>) c.getList(), person.getGender()))
c.getList().remove(person);
}
}
if (c.wasUpdated()) {
for (int update = c.getFrom(); update < c.getTo(); update++) {
Person person = c.getList().get(update);
if (checkCondition((ObservableList<Person>) c.getList(), person.getGender()))
person.setGender(Person.Gender.UNKNOWN);
}
}
}
}
};
people.addListener(listener);
此解决方案的唯一问题是,它实际上并没有 "revert" 更新更改,而是将性别设置为新的未知值。
如果你真的想恢复更改,解决方案可以是这样的:
this.people = FXCollections.observableArrayList();
ListChangeListener<Person> listener = new ListChangeListener<Person>() {
private boolean checkCondition(ObservableList<Person> list, Person.Gender gender) {
int males = 0;
int females = 0;
for (Person person : list) {
switch (person.getGender()) {
case MALE: males++; break;
case FEMALE: females++; break;
default: break;
}
}
return ((males > 10 && gender == Person.Gender.MALE) ||
(females > 5 && gender == Person.Gender.FEMALE));
}
@Override
public void onChanged(Change<? extends Person> c) {
while (c.next()) {
if (c.wasAdded()) {
for (Person person : c.getAddedSubList()) {
if (checkCondition((ObservableList<Person>) c.getList(), person.getGender()))
c.getList().remove(person);
else
person.genderProperty().addListener((obs, oldval, newval) -> {
if (checkCondition((ObservableList<Person>) c.getList(), newval))
person.setGender(oldval);
});
}
}
}
}
};
people.addListener(listener);
差异:提取器已被删除,因为在 ListChangeListener
内部仅包含元素的添加。当添加一个新元素时,其 genderProperty
上的侦听器已被添加,该侦听器检查性别更新,如果不满足条件,则该基因将恢复为原始基因。
您也可以通过不公开列表,而是公开操作列表的方法来实现相同的功能:addPersonAt
、removePersonAt
和 updateGenderAt
。