2015-11-17 42 views
0

我有一个ObservableMap,我想绑定到tableview,以显示映射值的一些属性,但映射中的新值未显示。在搜索和谷歌搜索我发现大部分相同的代码,但没有解决方案。绑定到TableView的ObservableMap不会更新新值

继承人是解释这个问题,唯一的解决方案',我发现一个SSCCE:创建一个新的ObservableList与地图的值,并将其设置为表每次地图上的变化,这是不是一个很棒的解决

public class MapTableBindTest extends Application { 

    int personIDCounter; 

    public static void main(String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) { 
     personIDCounter = 0; 
     // Map - TableView binding 
     ObservableMap<Integer, Person> map = FXCollections.observableHashMap(); 

     Person first = new Person("First", "Person"); // this person is mapped before the bind to the table 
     map.put(first.getID(), first);     // and because that, is shown on it 

     ObservableList<Map.Entry<Integer, Person>> list = FXCollections.observableArrayList(map.entrySet()); 
     TableView<Map.Entry<Integer, Person>> table = new TableView<>(list); 

     Person second = new Person("Second", "Person"); // once the bind has been setted no new items 
     map.put(second.getID(), second);    // are shown on the table. Same case when added in the UI 

     // Columns 
     TableColumn<Map.Entry<Integer, Person>, String> nameCol = new TableColumn<>("Name"); 
     nameCol.setCellValueFactory(cellData -> cellData.getValue().getValue().getName()); 
     TableColumn<Map.Entry<Integer, Person>, String> lastNameCol = new TableColumn<>("Surname"); 
     lastNameCol.setCellValueFactory(cellData -> cellData.getValue().getValue().getSurname()); 
     table.getColumns().addAll(nameCol, lastNameCol); 

     // View 
     BorderPane root = new BorderPane(); 
     TextField nameField = new TextField(); 
     TextField lastNameField = new TextField(); 
     Button addButton = new Button("Add"); 
     addButton.setOnMouseClicked(event -> { 
      Person newP = new Person(nameField.getText(), lastNameField.getText()); 
      map.put(newP.getID(), newP); // new items are not populated in the table... 
      nameField.clear(); 
      lastNameField.clear(); 
      //      ... unless a new observable list is created and setted to the table 
      ObservableList<Map.Entry<Integer, Person>> auxiliarList = FXCollections.observableArrayList(map.entrySet()); 
      table.setItems(auxiliarList); 
      //      commenting this two lines result with no updates shown in the table 
     }); 
     HBox TextHB = new HBox(nameField, lastNameField, addButton); 
     root.setTop(TextHB); 
     root.setCenter(table); 

     Scene scene = new Scene(root,400,500); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    // Sample class with some properties 
    class Person { 

     private int id; 
     private StringProperty name, surname; 

     public Person(String name, String surname) { 
      id = personIDCounter++; 
      this.name = new SimpleStringProperty(name); 
      this.surname = new SimpleStringProperty(surname); 
     } 

     public int getID() { 
      return id; 
     } 

     public StringProperty getName() { 
      return name; 
     } 

     public StringProperty getSurname() { 
      return surname; 
     } 
    } 
} 

可能什么是错与对ObservableList地图的entryset()之间的绑定。 Javadoc中说,大约entrySet()ObservableMap的:

返回包含在此映射中的映射关系的Set视图。 该集合由地图支持,因此对地图的更改将反映在集合中,反之亦然。(...)

这不是很明显,否则TableView会随着更改而更新。

(感谢James_D): 上ObservableMap此侦听添加/删除表中所示ObservableList,因此值的变化。当您添加项目,并通过entrySet()返回集也改变

map.addListener((MapChangeListener.Change<? extends Integer, ? extends Person> c) -> { 
     if (c.wasAdded()) { 
      Person added = c.getValueAdded(); 
      list.add(new AbstractMap.SimpleEntry<Integer, Person>(added.getID(), added)); 
     } else if (c.wasRemoved()) { 
      Person removed = c.getValueRemoved(); 
      list.remove(new AbstractMap.SimpleEntry<Integer, Person>(removed.getID(), removed)); 
     } 
    }); 

回答

0

您的地图正在发生变化。但是,该集合不是可观察集合,因此ObservableList不可能“看到”发生的任何更改。

相反,您需要将列表直接连接到地图。你可以通过使表查看TableView<Person>,然后与地图注册监听器,只需做到这一点:

map.addListener((Change<? extends Integer, ? extends Person> c) -> { 
    if (c.wasAdded()) { 
     list.add(c.getValueAdded()); 
    } else if (c.wasRemoved()) { 
     list.remove(c.getValueRemoved()); 
    } 
}); 

下面是完整的例子:

import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.MapChangeListener.Change; 
import javafx.collections.ObservableList; 
import javafx.collections.ObservableMap; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.HBox; 
import javafx.stage.Stage; 

public class MapTableBindTest extends Application { 

    int personIDCounter; 

    public static void main(String[] args) { 
     launch(args); 
    } 

    @Override 
    public void start(Stage primaryStage) { 
     personIDCounter = 0; 
     // Map - TableView binding 
     ObservableMap<Integer, Person> map = FXCollections.observableHashMap(); 

     Person first = new Person("First", "Person"); // this person is mapped before the bind to the table 
     map.put(first.getID(), first);     // and because that, is shown on it 

     ObservableList<Person> list = FXCollections.observableArrayList(map.values()); 
     TableView<Person> table = new TableView<>(list); 

     map.addListener((Change<? extends Integer, ? extends Person> c) -> { 
      if (c.wasAdded()) { 
       list.add(c.getValueAdded()); 
      } else if (c.wasRemoved()) { 
       list.remove(c.getValueRemoved()); 
      } 
     }); 

     Person second = new Person("Second", "Person"); // once the bind has been setted no new items 
     map.put(second.getID(), second);    // are shown on the table. Same case when added in the UI 

     // Columns 
     TableColumn<Person, String> nameCol = new TableColumn<>("Name"); 
     nameCol.setCellValueFactory(cellData -> cellData.getValue().getName()); 
     TableColumn<Person, String> lastNameCol = new TableColumn<>("Surname"); 
     lastNameCol.setCellValueFactory(cellData -> cellData.getValue().getSurname()); 
     table.getColumns().addAll(nameCol, lastNameCol); 

     // View 
     BorderPane root = new BorderPane(); 
     TextField nameField = new TextField(); 
     TextField lastNameField = new TextField(); 
     Button addButton = new Button("Add"); 
     addButton.setOnMouseClicked(event -> { 
      Person newP = new Person(nameField.getText(), lastNameField.getText()); 
      map.put(newP.getID(), newP); // new items are not populated in the table... 
      nameField.clear(); 
      lastNameField.clear(); 
     }); 
     HBox TextHB = new HBox(nameField, lastNameField, addButton); 
     root.setTop(TextHB); 
     root.setCenter(table); 

     Scene scene = new Scene(root,400,500); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    // Sample class with some properties 
    class Person { 

     private int id; 
     private StringProperty name, surname; 

     public Person(String name, String surname) { 
      id = personIDCounter++; 
      this.name = new SimpleStringProperty(name); 
      this.surname = new SimpleStringProperty(surname); 
     } 

     public int getID() { 
      return id; 
     } 

     public StringProperty getName() { 
      return name; 
     } 

     public StringProperty getSurname() { 
      return surname; 
     } 
    } 
} 
+0

谢谢!我正在尝试使用'Bindings'类,我想这可能是一些解决方法,使用javafx的预定义绑定 - 属性 - 监听器。我用解决方案编辑了这个问题 – ottogarcia