【问题标题】:How to convert an observableset to an observablelist如何将 observableset 转换为 observablelist
【发布时间】:2014-09-08 14:27:27
【问题描述】:

我正在尝试将项目设置为表视图,但 setitems 方法需要一个可观察列表,而我的模型中有一个可观察集。FXCollections 实用程序类没有在给定可观察集的情况下创建可观察列表的方法。我尝试强制转换但这导致了类转换异常(如预期的那样)。

目前我正在使用这种代码

new ObservableListWrapper<E>(new ArrayList<E>(pojo.getObservableSet()));

我有一些问题:

  • 在表格中进行编辑是否会按预期更新基础集?
  • 这是“正确”的做法吗

所以简而言之,我需要一个样式指南或最佳实践来在可观察集和可观察列表之间进行转换,因为我希望在构建 java fx GUI 时经常这样做

【问题讨论】:

  • 你试过FXCollections.observableArrayList(pojo.getObservableSet().toArray());
  • 谢谢,我会试试这个,但它比我上面的当前方法更好吗?

标签: java java-8 javafx-8 observable


【解决方案1】:

在表格中编辑它会按预期更新基础集吗?

不,因为,您正在复制该系列:

new ArrayList<E>(pojo.getObservableSet())

这是“正确”的做法吗?

我认为正确的方法是不这样做。 Set 不是 List,反之亦然。两者都有特定的限制。例如,列表是有序的,集合不包含重复元素。

此外,FXCollections 也没有Bindings 提供这种东西。

我希望集合保持为一个集合以强制唯一性

我猜你可以写一个自定义的ObservableList,例如Parent::children 有类似的行为。如果添加了重复的孩子,它会抛出一个IllegalArgumentException。如果您查看源代码,您会发现它是一个VetoableListDecorator 扩展名。你可以自己写:

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import com.sun.javafx.collections.VetoableListDecorator;

public class CustomObservableList<E> extends VetoableListDecorator<E> {

    public CustomObservableList(ObservableList<E> decorated) {
        super(decorated);
    }

    @Override
    protected void onProposedChange(List<E> toBeAdded, int... indexes) {
        for (E e : toBeAdded) {
            if (contains(e)) {
                throw new IllegalArgumentException("Duplicament element added");
            }
        }
    }
}

class Test {
    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();

        Set<Object> set = new HashSet<Object>();
        set.add(o1);
        CustomObservableList<Object> list = new CustomObservableList<Object>(FXCollections.observableArrayList(set));
        list.add(o2);
        list.add(o1); // throw Exception
    }
}

【讨论】:

  • 那么回到根本问题,如何让 tableview 显示基于集合的项目集合?我希望该集合保持为一组以强制唯一性
  • 请注意,这使用了 JavaFX 的内部“私有”API。这可能会中断(尤其是 Jigsaw,尽管会有一个命令行开关使其工作 - 至少在 JDK 9 中是这样)。如果您认为此 API 有用,可以创建一个问题,使其成为包含在公共 API 中的候选对象。
  • 你忘记了右括号 -> new ArrayList&lt;E&gt;(pojo.getObservableSet())(编辑需要超过 6 个字符,否则我会自己做)
【解决方案2】:

以防万一有人偶然发现这个问题,寻找一种将 ObservableSet 转换为 ObservableList 的单一方法......我发布了我的解决方案。它不支持将数据反馈到集合(在我看来这不太好,因为 TableView 没有不能更改值的概念)但支持集合的更新并保留(在此case) 排序顺序。

package de.fluxparticle.lab;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.ObservableSet;
import javafx.collections.SetChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.Collections;
import java.util.Random;
import java.util.TreeSet;

import static javafx.collections.FXCollections.observableSet;

/**
 * Created by sreinck on 23.01.17.
 */
public class Set2List extends Application {

    private final ObservableSet<Integer> setModel = observableSet(new TreeSet<Integer>());

    @Override
    public void start(Stage primaryStage) throws Exception {
        TableView<Integer> tableView = new TableView<>();
        addColumn(tableView, "Number");

        ObservableList<Integer> list = convertSetToList(setModel);
        tableView.setItems(list);

        Random rnd = new Random();
        scheduleTask(Duration.millis(1000), () -> setModel.add(rnd.nextInt(10)));

        primaryStage.setScene(new Scene(tableView, 800, 600));
        primaryStage.setTitle("Set2List");
        primaryStage.show();
    }

    private static void scheduleTask(Duration interval, Runnable task) {
        Timeline timeline = new Timeline(new KeyFrame(interval, event -> task.run()));
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();
    }

    private static ObservableList<Integer> convertSetToList(ObservableSet<Integer> set) {
        ObservableList<Integer> list = FXCollections.observableArrayList(set);

        set.addListener((SetChangeListener<Integer>) change -> {
            if (change.wasAdded()) {
                Integer added = change.getElementAdded();
                int idx = -Collections.binarySearch(list, added)-1;
                list.add(idx, added);
            } else {
                Integer removed = change.getElementRemoved();
                int idx = Collections.binarySearch(list, removed);
                list.remove(idx);
            }
        });

        return list;
    }

    private static void addColumn(TableView<Integer> tableView, String text) {
        TableColumn<Integer, String> column = new TableColumn<>(text);
        column.setCellValueFactory(param -> new SimpleStringProperty(param.getValue().toString()));
        tableView.getColumns().add(column);
    }

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

}    

【讨论】:

    猜你喜欢
    • 2014-04-07
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 2014-01-17
    • 2016-04-28
    相关资源
    最近更新 更多