java - 如何将模型属性与 TreeView 单元格中的复选框状态相关联?
问题描述
我正在用 JavaFX 编写一个简单的任务管理器应用程序。下面是我到目前为止写的简单代码
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class App extends Application {
class TaskClass {
public String task_Title;
public String task_Duration;
public String Remained_Days;
public boolean task_Is_Completed;
}
@Override
public void start(Stage primaryStage) {
TaskClass TaskClassObject = new TaskClass();
TaskClassObject.task_Title = "Buy a Car";
TaskClassObject.task_Duration = "7 days";
TaskClassObject.Remained_Days = "2 days";
TaskClassObject.task_Is_Completed = false;
TreeView<TaskClass> treeView = new TreeView<TaskClass>();
CheckBoxTreeItem<TaskClass> rootNode = new CheckBoxTreeItem<TaskClass>(TaskClassObject);
treeView.setRoot(rootNode);
treeView.setCellFactory(CheckBoxTreeCell.<TaskClass>forTreeView());
VBox vb = new VBox();
VBox.setVgrow(treeView, Priority.ALWAYS);
vb.getChildren().add(treeView);
Scene Scene = new Scene(vb, 800, 600);
primaryStage.setTitle("my task manager app");
primaryStage.setScene(Scene);
primaryStage.show();
}
public static void main(String[] args) {
launch();
}
}
我想遍历treeView
节点并获取TaskClassObject
每个节点的 并访问其字段(TaskClassObject.task_Title
和其他字段)并根据TaskClassObject.task_Is_Completed
. 如果为真,则应选中节点中的复选框。
解决方案
澄清方法信息
你说:
我想遍历 treeView 节点并获取每个节点的 TaskClassObject 并访问其字段(TaskClassObject.task_Title 和其他字段),并根据 TaskClassObject.task_Is_Completed 检查复选框。如果为真,则应选中节点中的复选框。
然而,这并不是你真正想做的。您不想尝试迭代事物并担心像 TreeView 这样的虚拟化控件中的节点和事物。
GUI 编程是事件驱动的,您要做的是响应事件并基于此更新关联的模型状态。
你真正需要问(和想要)的是:
如何将 CheckBoxTreeItem 中的选定值绑定到我的模型类,以便当关联 CheckBoxTreeCell 中的 CheckBox 被选中或取消选中时,我的模型类中的关联属性会更新以反映新值?
(我将您的问题标题更新为其中的一个子集,以便其他人在遇到相同问题时可以轻松找到它)。
如何实现所需的绑定
CheckBoxTreeItem
和类是相当高级的CheckBoxTreeCell
类,它们被设置为响应适当的事件并根据它们更新模型状态。您需要利用它们提供的高级接口来使它们真正可用。要为您的示例执行此操作,您需要:
使您的模型类(the
Task
)使用并公开 JavaFX 属性,以便 UI 可以根据属性值自动更新,并且 UI 的更新可以自动更新属性值。complete
将任务实例中的属性绑定到关联的CheckBoxTreeItem
. 这是通过双向绑定完成的,因此对完整属性的Task
更新将更新 UI 中的选择状态,反之亦然。task.completeProperty().bindBidirectional(treeItem.selectedProperty());
向 提供选定的属性绑定回调,以
CheckBoxTreeCell
将其与您的CheckBoxTreeItem
. 这实际上通常在默认情况下发生,但是,如果您还想要一个 StringConverter(在这种情况下您需要这样做),那么据我所知,您需要手动提供一个。提供一个 StringConverter
CheckBoxTreeCell
以便它可以Task
以清晰的方式显示您。
示例代码
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.StringConverter;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
public class App extends Application {
public static void main(String[] args) {
launch();
}
@Override
public void start(Stage stage) {
Task task = createTask();
CheckBoxTreeItem<Task> treeItem = new CheckBoxTreeItem<>(task);
task.completeProperty().bindBidirectional(treeItem.selectedProperty());
TreeView<Task> treeView = new TreeView<>();
attachTaskCellFactory(treeView);
treeView.setRoot(treeItem);
StackPane layout = new StackPane(treeView);
Scene Scene = new Scene(layout);
stage.setScene(Scene);
stage.show();
}
private void attachTaskCellFactory(TreeView<Task> treeView) {
Callback<TreeItem<Task>, ObservableValue<Boolean>> getSelectedProperty =
item -> {
if (item instanceof CheckBoxTreeItem<?>) {
return ((CheckBoxTreeItem<?>)item).selectedProperty();
}
return null;
};
StringConverter<TreeItem<Task>> treeItemStringConverter = new StringConverter<>() {
@Override
public String toString(TreeItem<Task> treeItem) {
return treeItem == null || treeItem.getValue() == null || treeItem.getValue().getTitle() == null
? ""
: treeItem.getValue().getTitle();
}
@Override
public TreeItem<Task> fromString(String string) {
// not actually used, only provided to allow a concrete instance to be created.
return null;
}
};
treeView.setCellFactory(
CheckBoxTreeCell.forTreeView(
getSelectedProperty,
treeItemStringConverter
)
);
}
private Task createTask() {
Task task = new Task(
"Buy a Car",
Duration.of(7, ChronoUnit.DAYS),
Duration.of(2, ChronoUnit.DAYS),
false
);
task.completeProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Task complete: " + newValue);
});
return task;
}
public class Task {
final private StringProperty title = new SimpleStringProperty();
final private ObjectProperty<Duration> duration = new SimpleObjectProperty<>();
final private ObjectProperty<Duration> remainingDays = new SimpleObjectProperty<>();
final private BooleanProperty complete = new SimpleBooleanProperty();
public Task(String title, Duration duration, Duration remainingDays, Boolean complete) {
setTitle(title);
setDuration(duration);
setRemainingDays(remainingDays);
setComplete(complete);
}
public String getTitle() {
return title.get();
}
public StringProperty titleProperty() {
return title;
}
public void setTitle(String title) {
this.title.set(title);
}
public Duration getDuration() {
return duration.get();
}
public ObjectProperty<Duration> durationProperty() {
return duration;
}
public void setDuration(Duration duration) {
this.duration.set(duration);
}
public Duration getRemainingDays() {
return remainingDays.get();
}
public ObjectProperty<Duration> remainingDaysProperty() {
return remainingDays;
}
public void setRemainingDays(Duration remainingDays) {
this.remainingDays.set(remainingDays);
}
public boolean isComplete() {
return complete.get();
}
public BooleanProperty completeProperty() {
return complete;
}
public void setComplete(boolean complete) {
this.complete.set(complete);
}
}
}
推荐阅读
- javascript - 如何使用偏移量将本地日期时间转换为 GMT
- javascript - Gulp 不会将图像移动到 dist 文件夹中
- c++ - 错误 C2664:MessageBoxW 无法将参数 2 从“const char”转换为“LPCWSTR”
- javascript - Mongoose 返回多个结果
- javascript - 我无法找到代码有什么问题。错误:TypeError:调度不是函数
- gradle - 使用 withType() 配置未在 IntelliJ 中编译的 Gradle 任务
- image - 如何使用按钮制作图像图标以更改图像,如谷歌:
- graphdb - 我可以检查形状图吗
- c# - CallerArgumentExpression 始终为空
- laravel - 如何将 Token 和数据插入 API 并显示结果