2017-02-24 36 views
0

假设我们有一个ObservableList<Person>其中Person具有属性:年龄,性别。目标是创建一个类似于 Map<Gender, Map<Age, List<Person>>>的可观察(所有级别)映射,我可以绑定到ObservableListJavaFX group通过多个参数将ObservableList绑定到地图并将它们绑定

这样做的原因是因为我必须基于这样的分组提取实时聚合数据。

+0

我只是想知道是否有可能使用(滥用?)'TreeItem'类来表示这样的数据。管理树项目类型可能会非常棘手(你需要'Gender'作为第一级项目的类型,'Integer'作为第二级作品,'Person'作为第三级作品,所以你可能需要使用'TreeItem 's)。但优点是['TreeItem'](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TreeItem.html)定义了一个事件结构,该结构在树上触发修改事件层次结构,这可能正是你在这里需要保持你的聚合数据最新。 –

回答

1

这需要你给听众中添加到每个属性和指定bean的属性,以避免为每个Person创造200名听众:

private final ObjectProperty<Gender> gender = new SimpleObjectProperty<>(this, "gender"); 
private final IntegerProperty age = new SimpleIntegerProperty(this, "age"); 
public static void main(String[] args) { 
    ObservableList<Person> data = FXCollections.observableArrayList(); 
    ObservableMap<Gender, ObservableMap<Number, ObservableList<Person>>> grouped = FXCollections.observableHashMap(); 
    ChangeListener<Gender> genderChangeListener = (observable, oldValue, newValue) -> { 
     ObservableMap<Number, ObservableList<Person>> m = grouped.get(oldValue); 
     Person person = (Person) ((Property) observable).getBean(); 

     // remove person from list and remove list, if it becomes empty 
     m.compute(person.getAge(), (a, lp) -> { 
      lp.remove(person); 
      return lp.isEmpty() ? null : lp; 
     }); 

     // remove age map, if it's empty 
     if (m.isEmpty()) { 
      grouped.remove(oldValue); 
     } 

     // add person at new position generating the Map/List, if necessary 
     grouped.computeIfAbsent(newValue, g -> FXCollections.observableHashMap()) 
       .computeIfAbsent(person.getAge(), a -> FXCollections.observableArrayList()) 
       .add(person); 
    }; 
    ChangeListener<Number> ageChangeListener = (observable, oldValue, newValue) -> { 
     Person person = (Person) ((Property) observable).getBean(); 
     ObservableMap<Number, ObservableList<Person>> map = grouped.get(person.getGender()); 

     // remove person from list and remove list, if it becomes empty 
     map.compute(oldValue, (a, lp) -> { 
      lp.remove(person); 
      return lp.isEmpty() ? null : lp; 
     }); 

     // add person at new position generating the List, if necessary 
     map.computeIfAbsent(newValue, a -> FXCollections.observableArrayList()) 
       .add(person); 
    }; 
    data.addListener((ListChangeListener.Change<? extends Person> c) -> { 
     while (c.next()) { 
      for (Person p : c.getRemoved()) { 
       // unregister the listeners of removed Persons 
       p.genderProperty().removeListener(genderChangeListener); 
       p.ageProperty().removeListener(ageChangeListener); 

       // remove person from grouped 
       ObservableMap<Number, ObservableList<Person>> m = grouped.get(p.getGender()); 
       m.compute(p.getAge(), (a, lp) -> { 
        lp.remove(p); 
        return lp.isEmpty() ? null : lp; 
       }); 
       if (m.isEmpty()) { 
        grouped.remove(p.getGender()); 
       } 
      } 
      for (Person p : c.getAddedSubList()) { 
       // add listeners to person 
       p.genderProperty().addListener(genderChangeListener); 
       p.ageProperty().addListener(ageChangeListener); 

       // add person to grouped generating the Map/List, if necessary 
       grouped.computeIfAbsent(p.getGender(), g -> FXCollections.observableHashMap()) 
         .computeIfAbsent(p.getAge(), a -> FXCollections.observableArrayList()) 
         .add(p); 
      } 
     } 
    }); 

    // test 
    Person p = new Person("Frank", Gender.MALE, 20); 
    Person p2 = new Person("Lisa", Gender.FEMALE, 32); 
    Person p3 = new Person("Nora", Gender.FEMALE, 52); 
    Person p4 = new Person("Carl", Gender.MALE, 62); 

    System.out.println(grouped); 
    data.addAll(p, p2, p3, p4); 
    System.out.println(grouped); 
    p3.setAge(32); 
    System.out.println(grouped); 
    p.setGender(Gender.FEMALE); 
    System.out.println(grouped); 
    data.remove(p3); 
    System.out.println(grouped); 
    data.remove(p4); 
    System.out.println(grouped); 
}