Javafx tableview 项目防止重复 [英] Javafx tableview items prevent duplicates

查看:51
本文介绍了Javafx tableview 项目防止重复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用带有 observableList 列表的 javafx tableview,我试图防止列表包含重复的项目.在进行了一些搜索之后,我发现 observableSet 可以通过覆盖方法:equals() 和 hashcode() 来完成这项工作.

I'm using javafx tableview with observableList list, I tried to prevent list from holding duplicate items. After doing some search, i figure out that an observableSet can do this job by overidding thoes methodes:equals() and hashcode().

但是javaFX tableview不能持有observable set的问题:

But the problem that javaFX tableview can't hold an observable set:

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

我还计划为我的 tableview 中的列计算一些,所以,我需要

I also planned to calculate the some for a columns in my tableview so, i need

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

我真的很困惑正确的方法来做到这一点.所以,我需要你的提示

I really confused about the right way to do this. So, i need your hints

推荐答案

你可以创建一个 ObservableSet 然后添加一个监听器来更新一个 ObservableList 使用作为表的项目列表.只要不直接对表的项目进行修改(仅对集合进行修改,您可以通过对表使用不可修改的列表来强制执行),那么该表将始终包含与集合完全相同的项目.

You can create an ObservableSet and then add a listener to it which updates an ObservableList which is used as the items list for the table. As long as modifications are not made directly to the table's items (only to the set, which you can enforce by using an unmodifiable list for the table), then the table will always contain exactly the same items as the set.

要跟踪列表中所有项目的属性值的总和,您需要可以向列表注册一个侦听器,并在更改时重新计算总和.如果属性本身可能发生变化,您可以在创建列表时使用提取器,以便在任何列表元素的属性发生更改时,列表将触发更新通知.

To track the total of the values of a property of all the items in the list, you need can register a listener with the list, and recompute the total when it changes. If the property itself may change, you can use an extractor when you create the list, so that the list will fire update notifications if that property changes for any of the list elements.

这个例子将所有这些拼凑在一起.与按钮相关的修改方法都在ObservableSet上操作.请注意,如果您尝试添加一个与现有项目相等的项目,则不会发生任何变化(因为添加到集合中没有任何作用,因此不会触发列表的更新).

This example pieces all this together. The modification methods associated with the buttons all operate on the ObservableSet. Notice that if you try to add an item which is equal to an existing item, nothing changes (because adding to the set does nothing, and so no updates are fired to the list).

您可以使用递增和递减按钮选择和修改现有项目,您将看到更新反映在总数中.

You can select and modify existing items using the increment and decrement buttons, and you'll see the updates reflected in the total.

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);
    }
}

这篇关于Javafx tableview 项目防止重复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆