在 CellFactory 中有条件地提供不同的 TreeCell
Provide different TreeCell conditionally in CellFactory
我有一个树视图,其中的单元格必须根据 TreeItem's value 的实际实现显示不同的信息。
我的域模型如下所示:
对我来说,将 "how to display a Task in a cell" 或 "how to display a Group in a cell" 的行为分成两个不同的 class 似乎很自然。
public abstract class ComponentTreeCell<T extends Component> extends TreeCell<T>
{
@Override
protected void updateItem(T item, boolean empty)
{
//Some common logic...
}
}
public class GroupTreeCell extends ComponentTreeCell<Group>
{
@Override
protected void updateItem(Group item, boolean empty)
{
super.updateItem(item, empty);
//Some group-specific-logic
}
}
public class TaskTreeCell extends ComponentTreeCell<Task>
{
@Override
protected void updateItem(Task item, boolean empty)
{
super.updateItem(item, empty);
//Some task-specific-logic
}
}
以下控制器 class 包含一个 TreeView 我在其中设置 CellFactory。
public class Controller implements Initializable
{
@FXML
private TreeView<Component> treeview;
@Override
public void initialize(URL url, ResourceBundle bundle)
{
treeview.setCellFactory(new Callback<TreeView<Component>, TreeCell<Component>>()
{
@Override
public TreeCell<Component> call(TreeView<Component> arg0)
{
if(/* stuck */ instanceof Group)
{
return new GroupTreeCell();
}
else if(/* stuck */ instanceof Task)
{
return new TaskTreeCell();
}
else
{
return new DefaultTreeCell();
}
}
});
}
}
但是我现在陷入困境,无法决定我必须使用哪种类型的单元 return。事实上,我只有参数相关的 TreeView 和 而不是相关的 TreeItem !
在我看来,这像是 JavaFX 的一种弱点。当您只需要检索一个 TreeCell 时,为什么 JavaFX 将完整的 TreeView 提供给用户??
有没有办法以这种方式做到这一点,或者我是否必须在同一个自定义 TreeCell 实现中实现 2 种不同的行为?
public class ComponentTreeCell extends TreeCell<Component>
{
@Override
protected void updateItem(Component item, boolean empty)
{
//Some common logic...
if(item instanceof Group)
{
//Group-specific logic...
}
else if(item instanceof Task)
{
//Task-specific logic...
}
else
{
//Default logic...
}
}
}
Why JavaFX gives the full TreeView to the user when you only need to retrieve one TreeCell ??
因为 TreeItem
和 TreeCell
之间没有一对一的关系:TreeView
只会创建少量的 TreeCell
(即使树有非常多的项目)。 TreeCell
被重新用于显示不同的 TreeItem
,例如,如果某些节点是 expanded/collapsed,或者如果用户滚动。
这样做是为了性能。提供渲染的实际单元格是相当大的对象:它们是 UI 组件并带有 CSS 样式等。显示的实际数据,即 TreeItem
相对轻量级;通常它们只是 String
的简单包装器。所以这种机制允许 TreeView
s 包含大量数据,不会对性能造成巨大负担。为每个 TreeItem
创建一个 TreeCell
是不允许的。
因此,您从工厂提供的 TreeCell
必须能够处理 TreeView
可能提供给它的任何 TreeItem
。例如,当用户更改显示的项目(通过 expanding/collapsing 或通过滚动)时,先前显示 Task
的 TreeCell
实例可能会用于显示 Group
.这就是 updateItem(...)
方法的目的;它在 TreeCell
被重用时被调用。
这意味着您的设置根本不起作用。在上一个代码示例中,您基本上需要 TreeCell<Component>
实现。如果愿意,您当然可以将配置分解为单独的 类,例如:
public class ComponentTreeCell extends TreeCell<Component>
{
@Override
protected void updateItem(Component item, boolean empty)
{
super.updateItem(item, empty);
CellConfiguratorFactory.getConfigurator(item).configure(this, item, empty);
}
}
工厂:
public class CellConfiguratorFactory {
private static CellConfigurator<Task> taskCellConfigurator ;
private static CellConfigurator<Group> groupCellConfigurator ;
private static CellConfigurator<Component> defaultCellConfigurator ;
private static CellConfigurator getConfigurator(Component item) {
if (item instanceof Task) {
if (taskCellConfigurator == null) {
taskCellConfigurator = new TaskCellConfigurator();
}
return taskCellConfigurator ;
} else if (item instanceof Group) {
if (groupCellConfigurator == null) {
groupCellConfigurator = new GroupCellConfigurator();
}
return groupCellConfigurator ;
} else {
if (defaultCellConfigurator == null) {
defaultCellConfigurator = new DefaultCellConfigurator();
}
return defaultCellConfigurator ;
}
}
}
(请注意,您可以假设工厂只在单个线程中使用,因为一切都将发生在 FX 应用程序线程上。)
然后
public interface CellConfigurator<T extends Component> {
public void configureCell(ComponentTreeCell cell, T item, boolean empty);
}
例如,
public class TaskCellConfigurator implements CellConfigurator<Task> {
public void configureCell(TreeCell<Component> cell, Task item, boolean empty) {
// task-specific implementation...
}
}
但是,我不确定额外的结构是否值得在这里付出努力。
我有一个树视图,其中的单元格必须根据 TreeItem's value 的实际实现显示不同的信息。
我的域模型如下所示:
对我来说,将 "how to display a Task in a cell" 或 "how to display a Group in a cell" 的行为分成两个不同的 class 似乎很自然。
public abstract class ComponentTreeCell<T extends Component> extends TreeCell<T>
{
@Override
protected void updateItem(T item, boolean empty)
{
//Some common logic...
}
}
public class GroupTreeCell extends ComponentTreeCell<Group>
{
@Override
protected void updateItem(Group item, boolean empty)
{
super.updateItem(item, empty);
//Some group-specific-logic
}
}
public class TaskTreeCell extends ComponentTreeCell<Task>
{
@Override
protected void updateItem(Task item, boolean empty)
{
super.updateItem(item, empty);
//Some task-specific-logic
}
}
以下控制器 class 包含一个 TreeView 我在其中设置 CellFactory。
public class Controller implements Initializable
{
@FXML
private TreeView<Component> treeview;
@Override
public void initialize(URL url, ResourceBundle bundle)
{
treeview.setCellFactory(new Callback<TreeView<Component>, TreeCell<Component>>()
{
@Override
public TreeCell<Component> call(TreeView<Component> arg0)
{
if(/* stuck */ instanceof Group)
{
return new GroupTreeCell();
}
else if(/* stuck */ instanceof Task)
{
return new TaskTreeCell();
}
else
{
return new DefaultTreeCell();
}
}
});
}
}
但是我现在陷入困境,无法决定我必须使用哪种类型的单元 return。事实上,我只有参数相关的 TreeView 和 而不是相关的 TreeItem !
在我看来,这像是 JavaFX 的一种弱点。当您只需要检索一个 TreeCell 时,为什么 JavaFX 将完整的 TreeView 提供给用户??
有没有办法以这种方式做到这一点,或者我是否必须在同一个自定义 TreeCell 实现中实现 2 种不同的行为?
public class ComponentTreeCell extends TreeCell<Component>
{
@Override
protected void updateItem(Component item, boolean empty)
{
//Some common logic...
if(item instanceof Group)
{
//Group-specific logic...
}
else if(item instanceof Task)
{
//Task-specific logic...
}
else
{
//Default logic...
}
}
}
Why JavaFX gives the full TreeView to the user when you only need to retrieve one TreeCell ??
因为 TreeItem
和 TreeCell
之间没有一对一的关系:TreeView
只会创建少量的 TreeCell
(即使树有非常多的项目)。 TreeCell
被重新用于显示不同的 TreeItem
,例如,如果某些节点是 expanded/collapsed,或者如果用户滚动。
这样做是为了性能。提供渲染的实际单元格是相当大的对象:它们是 UI 组件并带有 CSS 样式等。显示的实际数据,即 TreeItem
相对轻量级;通常它们只是 String
的简单包装器。所以这种机制允许 TreeView
s 包含大量数据,不会对性能造成巨大负担。为每个 TreeItem
创建一个 TreeCell
是不允许的。
因此,您从工厂提供的 TreeCell
必须能够处理 TreeView
可能提供给它的任何 TreeItem
。例如,当用户更改显示的项目(通过 expanding/collapsing 或通过滚动)时,先前显示 Task
的 TreeCell
实例可能会用于显示 Group
.这就是 updateItem(...)
方法的目的;它在 TreeCell
被重用时被调用。
这意味着您的设置根本不起作用。在上一个代码示例中,您基本上需要 TreeCell<Component>
实现。如果愿意,您当然可以将配置分解为单独的 类,例如:
public class ComponentTreeCell extends TreeCell<Component>
{
@Override
protected void updateItem(Component item, boolean empty)
{
super.updateItem(item, empty);
CellConfiguratorFactory.getConfigurator(item).configure(this, item, empty);
}
}
工厂:
public class CellConfiguratorFactory {
private static CellConfigurator<Task> taskCellConfigurator ;
private static CellConfigurator<Group> groupCellConfigurator ;
private static CellConfigurator<Component> defaultCellConfigurator ;
private static CellConfigurator getConfigurator(Component item) {
if (item instanceof Task) {
if (taskCellConfigurator == null) {
taskCellConfigurator = new TaskCellConfigurator();
}
return taskCellConfigurator ;
} else if (item instanceof Group) {
if (groupCellConfigurator == null) {
groupCellConfigurator = new GroupCellConfigurator();
}
return groupCellConfigurator ;
} else {
if (defaultCellConfigurator == null) {
defaultCellConfigurator = new DefaultCellConfigurator();
}
return defaultCellConfigurator ;
}
}
}
(请注意,您可以假设工厂只在单个线程中使用,因为一切都将发生在 FX 应用程序线程上。)
然后
public interface CellConfigurator<T extends Component> {
public void configureCell(ComponentTreeCell cell, T item, boolean empty);
}
例如,
public class TaskCellConfigurator implements CellConfigurator<Task> {
public void configureCell(TreeCell<Component> cell, Task item, boolean empty) {
// task-specific implementation...
}
}
但是,我不确定额外的结构是否值得在这里付出努力。