2016-02-03 3 views
2

Я использую javafx tableview с наблюдаемым списком list, я пытался предотвратить список из повторяющихся элементов. После выполнения какого-либо поиска я выясню, что наблюдаемый набор может выполнять эту работу, переопределяя методы метода: equals() и hashcode().Элементы табличного представления Javafx предотвращают дубликаты

Но проблема, что JavaFX TableView не может держать наблюдаемый набор:

tableView.setItems(FXCollections.observableSet(new hashSet<T>()); 

Я также планировал рассчитать некоторые за столбцов в моем Tableview так, что мне нужно

// After change in element T the total will change 
    ObservableList<T> listItems = FXCollections.observableArrayList(
       T -> new Observable[]{T.doSomeCalculeProperty}); 

I действительно запутался в правильном способе сделать это. Итак, мне нужны ваши подсказки

+0

Для первой части вопроса вы можете создать ObservableList, используя 'FXCollections.observableArrayList (set);'. Я не уверен, что именно вы хотите во второй части вашего вопроса. – ItachiUchiha

ответ

2

Вы можете создать ObservableSet, а затем добавить к нему слушателя, который обновит ObservableList, который используется как список элементов для таблицы. До тех пор, пока изменения не будут внесены непосредственно в элементы таблицы (только в набор, который можно выполнить с помощью немодифицируемого списка для таблицы), тогда таблица всегда будет содержать точно такие же элементы, что и набор.

Чтобы отслеживать общее количество значений свойства всех элементов в списке, вам необходимо зарегистрировать прослушиватель со списком и пересчитать общее количество при его изменении. Если это свойство может измениться, вы можете использовать экстрактор при создании списка, чтобы список активировал уведомления об обновлениях, если это свойство изменяется для любого из элементов списка.

Этот пример объединяет все это вместе. Методы модификации, связанные с кнопками, все работают на ObservableSet. Обратите внимание, что если вы попытаетесь добавить элемент, который равен существующему элементу, ничего не изменится (поскольку добавление в набор ничего не делает, и поэтому в список не добавляются обновления).

Вы можете выбирать и изменять существующие элементы с помощью кнопок увеличения и уменьшения, и вы увидите обновления, отраженные в итоговом.

import java.util.HashSet; 
import java.util.Objects; 
import java.util.stream.Collectors; 

import javafx.application.Application; 
import javafx.beans.Observable; 
import javafx.beans.binding.Bindings; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ListChangeListener; 
import javafx.collections.ObservableList; 
import javafx.collections.ObservableSet; 
import javafx.collections.SetChangeListener.Change; 
import javafx.geometry.Insets; 
import javafx.geometry.Pos; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.control.SelectionMode; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.TextField; 
import javafx.scene.control.TextFormatter; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.HBox; 
import javafx.stage.Stage; 

public class UniqueItemTableViewWithTotal extends Application { 

    // creates a table view which always contains the same items as the provided set 
    private TableView<Item> createTableView(ObservableSet<Item> items, IntegerProperty total) { 

     TableView<Item> table = new TableView<>(); 
     table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 

     // Want the table's items list to fire updates if the value of any item changes 
     // This allows observing the list for tracking the total of all values 
     ObservableList<Item> itemList = FXCollections.observableArrayList(
       item -> new Observable[] {item.valueProperty()}); 

     // register a listener with the set and update the list if the set changes 
     // this ensures the list will always contain the same elements as the list, 
     items.addListener((Change<? extends Item> c) -> { 
      if (c.wasAdded()) { 
       itemList.add(c.getElementAdded()); 
      } 
      if (c.wasRemoved()) { 
       itemList.remove(c.getElementRemoved()); 
      } 
     }); 

     // usual column setup 
     TableColumn<Item, String> nameCol = new TableColumn<>("Item"); 
     nameCol.setCellValueFactory(cellData -> cellData.getValue().nameProperty()); 
     TableColumn<Item, Integer> valueCol = new TableColumn<>("Value"); 
     valueCol.setCellValueFactory(cellData -> cellData.getValue().valueProperty().asObject()); 

     table.getColumns().add(nameCol); 
     table.getColumns().add(valueCol); 

     // use an unmodifiable list for the table to prevent any direct updates to the 
     // table's list (updates must go through the set) 
     table.setItems(FXCollections.unmodifiableObservableList(itemList)); 

     // update total if the items list changes: 
     itemList.addListener((ListChangeListener.Change<? extends Item> c) -> 
      total.set(itemList.stream() 
        .collect(Collectors.summingInt(Item::getValue)))); 

     // add any existing elements: 
     itemList.addAll(items); 

     return table ; 
    } 


    @Override 
    public void start(Stage primaryStage) { 
     ObservableSet<Item> items = FXCollections.observableSet(new HashSet<>()); 
     IntegerProperty total = new SimpleIntegerProperty(); 

     TableView<Item> table = createTableView(items, total); 

     for (int i = 1; i <=5 ; i++) { 
      items.add(new Item("Item "+i, 1+(int)(Math.random()*20))); 
     } 

     // label to display the total of all values: 
     Label totalLabel = new Label(); 
     totalLabel.textProperty().bind(total.asString("Total: %d")); 
     totalLabel.setStyle("-fx-font-size:24; -fx-padding:10;"); 

     // text fields for new item: 
     TextField itemField = new TextField(); 
     TextField valueField = new TextField(); 

     // restrict value field to valid integers: 
     valueField.setTextFormatter(new TextFormatter<Integer>(c -> 
       c.getControlNewText().matches("-?\\d*") ? c : null)); 

     // button to add new item: 
     Button addButton = new Button("Add"); 
     addButton.setOnAction(e -> { 
      Item item = new Item(itemField.getText(), Integer.parseInt(valueField.getText())); 
      items.add(item); 
      itemField.clear(); 
      valueField.clear(); 
     }); 
     addButton.disableProperty().bind(itemField.textProperty().isEmpty() 
       .or(valueField.textProperty().isEmpty())); 

     ObservableList<Item> selection = table.getSelectionModel().getSelectedItems(); 

     // button to remove selected item(s): 
     Button removeButton = new Button("Delete"); 
     removeButton.setOnAction(e -> 
       items.removeIf(new HashSet<Item>(selection)::contains)); 
     removeButton.disableProperty().bind(Bindings.isEmpty(selection)); 

     // button to increment selected item(s): 
     Button incButton = new Button("Increment"); 

     incButton.setOnAction(e -> selection.forEach(Item::increment)); 
     incButton.disableProperty().bind(Bindings.isEmpty(selection)); 

     // button to decrement selected item(s): 
     Button decButton = new Button("Decrement"); 
     decButton.setOnAction(e -> selection.forEach(Item::decrement)); 
     decButton.disableProperty().bind(Bindings.isEmpty(selection)); 

     HBox controls = new HBox(5, itemField, valueField, addButton, removeButton, incButton, decButton); 
     controls.setAlignment(Pos.CENTER); 
     controls.setPadding(new Insets(5)); 

     BorderPane root = new BorderPane(table); 
     root.setTop(totalLabel); 
     root.setBottom(controls); 

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

    // model item: 
    public static class Item { 
     private final StringProperty name = new SimpleStringProperty(); 
     private final IntegerProperty value = new SimpleIntegerProperty(); 

     public Item(String name, int value) { 
      setName(name); 
      setValue(value); 
     } 

     public final StringProperty nameProperty() { 
      return this.name; 
     } 


     public final String getName() { 
      return this.nameProperty().get(); 
     } 


     public final void setName(final String name) { 
      this.nameProperty().set(name); 
     } 


     public final IntegerProperty valueProperty() { 
      return this.value; 
     } 


     public final int getValue() { 
      return this.valueProperty().get(); 
     } 


     public final void setValue(final int value) { 
      this.valueProperty().set(value); 
     } 


     public void increment() { 
      setValue(getValue()+1); 
     } 

     public void decrement() { 
      setValue(getValue()-1); 
     } 

     @Override 
     public int hashCode() { 
      return Objects.hash(getName(), getValue()); 
     } 

     @Override 
     public boolean equals(Object o) { 
      if (o.getClass() != Item.class) { 
       return false ; 
      } 
      Item other = (Item) o ; 
      return Objects.equals(getName(), other.getName()) 
        && getValue() == other.getValue() ; 
     } 
    } 

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

Если таблица доступна для редактирования, единственным способом является создание собственной фабрики ячеек и проверка дубликатов вручную? – user1803551

Смежные вопросы