在单个TableView中显示不同的ObservableList [JavaFX]

时间:2017-04-04 19:08:00

标签: java javafx

我的布局基本上由ChoiceBoxTableView组成。我想要实现的是根据TableView中选定的选项在ChoiceBox中显示不同的数据。

到目前为止我所拥有的是:

MainController 类:

private void configureChoiceBox() {
        choiceBox.getSelectionModel().selectedIndexProperty().addListener((v, oldValue, newValue) -> {
            if(newValue.intValue() == 0) {
                workshopList.setItems(data.getPipeCableList());
            }
            else if(newValue.intValue() == 1) {
                workshopList.setItems(data.getElementList());
            }
        });
    }

数据类:

    private ObservableList<PipeCable> pipeCableList;
    private ObservableList<Element> elementList;
    /**/
    private ObservableList<StoredItem> displayedList;

    public Data() {
        this.pipeCableList = FXCollections.observableArrayList();
        this.elementList = FXCollections.observableArrayList();
        /**/
        this.displayedList = FXCollections.observableArrayList();
    }

    public ObservableList<StoredItem> getPipeCableList() {
    displayedList.removeAll(elementList);   
    displayedList.addAll(pipeCableList);
        return displayedList;
    }

    public ObservableList<StoredItem> getElementList() {
    displayedList.removeAll(pipeCableList); 
    displayedList.addAll(elementList);
        return displayedList;
    }

问题是:当我在ChoiceBox中的选项之间进行更改时,来自elementListpipeCableList的数据混合在一起并更改{{1}中的选项没有任何结果。

我想要实现的目标:根据{{1}选择的选项,能够显示ChoiceBoxelementList中包含的不同数据}。而且,当选择一个选项(显示一个列表)时,添加到该列表的所有新项目将在pipeCableList上可见。

编辑(添加缺失信息): ChoiceBoxTableView延伸PipeCableElement获取StoredItem类型的项目。

1 个答案:

答案 0 :(得分:1)

出了什么问题

摆脱displayList,TableView已经引用了它显示的项目列表,所以只需将其设置为适当的列表即可。目前,您的显示列表值与基础数据值不同步。

假设

我假设您的TableView采用StoredItem类型的项目,并且PipeCable和Element也是StoredItem类型(尽管继承或接口实现)。

如何解决

通常,您可以这样做:

tableView.setItems(data.getPipeCableList()) 
选择时,

和元素列表相同。但由于Java泛型的一些限制,我似乎无法轻易绕过,但这不能编译。如果元素列表和管道电缆列表都是相同的类型(而不是普通父类型的子元素),那就不会有问题。

要解决泛型问题,您可以:

tableView.getItems().setAll(data.getPipeCableList())

哪个工作正常,但如果数据项发生更改,则不会使表视图项与数据项保持同步。

为了使这些保持同步,你可以这样做:

Bindings.bindContent(tableView.getItems(), data.getPipeCableList());

这有点难看,但似乎有用。

完整示例应用

sample

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.*;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.stream.IntStream;

public class MultiListTable extends Application {
    enum ItemType {
        PipeCable, Element
    }

    @Override public void start(Stage stage) throws IOException {
        TableView<StoredItem> tableView = new TableView<>();

        TableColumn<StoredItem, String> nameColumn = new TableColumn<>("Name");
        nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
        nameColumn.setPrefWidth(120);

        tableView.getColumns().add(nameColumn);

        Data data = new Data();

        ChoiceBox<ItemType> choiceBox = new ChoiceBox<>(
                FXCollections.observableArrayList(ItemType.values())
        );

        choiceBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            switch (newValue) {
                case PipeCable:
                    Bindings.bindContent(tableView.getItems(), data.getPipeCableList());
                    break;

                case Element:
                    Bindings.bindContent(tableView.getItems(), data.getElementList());
                    break;
            }
        });

        choiceBox.getSelectionModel().select(0);

        Button addPipe = new Button("Add Pipe");
        addPipe.setOnAction(event -> data.getPipeCableList().add(
                new PipeCable("Pipe " + (data.getPipeCableList().size() + 1))
        ));
        IntStream.range(0, 3).forEach(i -> addPipe.fire());

        Button addElement = new Button("Add Element");
        addElement.setOnAction(event -> data.getElementList().add(
                new Element("Element " + (data.getElementList().size() + 1))
        ));
        IntStream.range(0, 2).forEach(i -> addElement.fire());

        HBox controls = new HBox(10, choiceBox, addPipe, addElement);

        VBox layout = new VBox(10, controls, tableView);
        layout.setPadding(new Insets(10));

        Scene scene = new Scene(layout);
        stage.setScene(scene);
        stage.show();
    }

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

    class Data {
        private ObservableList<PipeCable> pipeCableList = FXCollections.observableArrayList();
        private ObservableList<Element> elementList = FXCollections.observableArrayList();

        ObservableList<PipeCable> getPipeCableList() {
            return pipeCableList;
        }

        ObservableList<Element> getElementList() {
            return elementList;
        }
    }

    static public class StoredItem {
        private final ReadOnlyStringWrapper name;

        public StoredItem(String name) {
            this.name = new ReadOnlyStringWrapper(name);
        }

        public String getName() {
            return name.get();
        }

        public ReadOnlyStringProperty nameProperty() {
            return name.getReadOnlyProperty();
        }
    }

    static public class PipeCable extends StoredItem {
        public PipeCable(String name) {
            super(name);
        }
    }

    static public class Element extends StoredItem {
        public Element(String name) {
            super(name);
        }
    }
}