我有一个在单独线程中运行的模型类(实现任务)。它有一个在无限循环期间更新的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/