JavaFX 列表数据绑定(bind)

标签 java javafx data-binding

我有一个在单独线程中运行的模型类(实现任务)。它有一个在无限循环期间更新的ArrayList

private List<ClientSession> clientSessions = new ArrayList<>();

在 Controller 类中,我需要对此列表进行单向绑定(bind),该列表具有 ChangeListener 并显示在 TableView 中。

你能帮助我了解如何以最佳方式做到这一点(绑定(bind))吗?

我已经弄清楚如何进行内容绑定(bind)。

在模型类中我添加了:

public ObservableList<ClientSession> clientSessions = FXCollections.observableArrayList();

在 Controller 类中我添加了:

private ListProperty<ClientSession> clientSessionListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
clientSessionListProperty.bindContent(commandCenterNio.clientSessions);

但这并不能解决 tableview 的问题。如何在本例中使用TableView

最佳答案

实际上你不需要中间属性,ObservableList默认情况下是“可绑定(bind)的”,因为它会告诉您每当在列表上执行更改时:

A list that allows listeners to track changes when they occur.

您所要做的就是通过调用 setItems 直接为 ListView 提供模型的 ObservableList .

我准备了一个例子:

该示例有一个实现 Runnable 的模型(但请注意,它在无限循环中更新其列表这一事实对于解决方案来说绝对没有区别 ),它有一个 ToDo 对象的 ObservableList,它必须具有 Property 才能显示在 TableView 上。在 Main 中,模型填充了一些初始数据,并且 ListView 与数据一起显示。 GUI 还具有一些控件,可通过其缓冲区向模型添加新项目。

SampleModel.java

public class SampleModel implements Runnable{

    // Listen to this list
    public ObservableList<ToDo> toDoList = FXCollections.observableArrayList();

    // Buffer to be used to store new elements until the thread wakes up
    private BlockingQueue<ToDo> queue = new ArrayBlockingQueue<ToDo>(1000);

    @Override
    public void run() { 
        while(true){
            // Drain the buffer to the ObservableList
            queue.drainTo(toDoList);

            // Sleep a bit
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        } 
        }

    public void updateBuffer(ToDo newItem){
        queue.offer(newItem);
    }
}

ToDo.java

public class ToDo {

    private StringProperty task = new SimpleStringProperty();
    public StringProperty taskProperty() {return task;}

    private ObjectProperty<Importance> importance = new SimpleObjectProperty<Importance>();
    public ObjectProperty<Importance> importanceProperty() {return importance;}

    public ToDo(String task, Importance importance){
        this.task.set(task);
        this.importance.set(importance);
    }


    enum Importance {
        DONTCARE, SHALL, MUST, FIRSTPRIO;

          @Override
          public String toString() {
            switch(this) {
              case DONTCARE: return "I don't care";
              case SHALL: return "It shall be done";
              case MUST: return "It must be done";
              case FIRSTPRIO: return "I will die if I do not do it";
              default: throw new IllegalArgumentException();
            }
          }
    }

}

Main.java

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            VBox root = new VBox();
            Scene scene = new Scene(root,400,400);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());

            SampleModel model = new SampleModel();
            model.toDoList.addAll(new ToDo("Brooming", ToDo.Importance.DONTCARE),
                    new ToDo("Taking a nap", ToDo.Importance.FIRSTPRIO),
                    new ToDo("Cooking", ToDo.Importance.MUST),
                    new ToDo("Wash the car", ToDo.Importance.DONTCARE),
                    new ToDo("Pay the bills", ToDo.Importance.SHALL));

            TableView<ToDo> tableView = new TableView<ToDo>();

            TableColumn<ToDo, String> colTask = new TableColumn<ToDo, String>();
            colTask.setCellValueFactory(new PropertyValueFactory<>("task"));

            TableColumn<ToDo, String> colImportance = new TableColumn<ToDo, String>();
            colImportance.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().importanceProperty().get().toString()));

            tableView.getColumns().addAll(colTask, colImportance);

            tableView.setItems(model.toDoList);

            HBox hbox = new HBox();
            TextArea textArea = new TextArea();
            textArea.setPrefSize(180, 15);
            ComboBox<ToDo.Importance> cb = new ComboBox<ToDo.Importance>();
            cb.setItems(FXCollections.observableArrayList(ToDo.Importance.FIRSTPRIO, ToDo.Importance.DONTCARE, ToDo.Importance.MUST));

            Button btnAdd = new Button("Add");
            btnAdd.setOnAction(e -> model.updateBuffer(new ToDo(textArea.getText(), cb.getValue())));

            hbox.getChildren().addAll(textArea, cb, btnAdd);
            root.getChildren().addAll(hbox, tableView);

            Thread thread = new Thread(model);
            thread.setDaemon(true);
            thread.start();


            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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

关于JavaFX 列表数据绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37619096/

相关文章:

c# - 编辑绑定(bind)到同一绑定(bind)源的 TextEdits 中的 GridControl 中选择的多行

java - 在 Clojure 中覆盖 java 父类(super class)方法

JavaFx 13 - TableView Vertical ScrollBar 处理程序返回 NullPointerException

java - 将数字插入有序arrayList

java - 使用 Android 的 Spring Boot 将图像保存到服务器目录

javafx-2 - 如何拖动JavaFX的未修饰窗口(阶段)

c# - 如何使数据绑定(bind)类型安全并支持重构?

c# - 将模型中的数据对象集合绑定(bind)到 View 中的一组控件 (WPF)

java - 为什么只为减法二元运算符生成此错误?

java - 尝试将 double[][] 数组输入到 JTable 中