Conversation
There was a problem hiding this comment.
Pull request overview
该 PR 在 HMCL 内的 com.jfoenix.controls 包中补充了 JFoenix 风格的 TreeView 及其 TreeCell 实现,意图为树形控件提供 Material 风格的交互与选择指示能力。
Changes:
- 新增
JFXTreeView:为TreeView设置默认cellFactory并注册jfx-tree-view样式类 - 新增
JFXTreeCell:加入JFXRippler涟漪效果与左侧选择指示条,并处理 TreeItem graphic 的刷新
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| HMCL/src/main/java/com/jfoenix/controls/JFXTreeView.java | 新增 JFoenix TreeView 包装类:默认 cellFactory + 样式类注册 |
| HMCL/src/main/java/com/jfoenix/controls/JFXTreeCell.java | 新增 JFoenix TreeCell:涟漪效果、选择条与显示逻辑 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| public JFXTreeCell() { | ||
| selectedPane.getStyleClass().add("selection-bar"); | ||
| selectedPane.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY))); |
There was a problem hiding this comment.
selectedPane背景色被硬编码为 Color.RED,这会绕过主题/CSS,且与现有 JFoenix 控件普遍通过样式表定制的方式不一致。建议移除代码里的 Background 设置,只保留 style class(例如 selection-bar),并在 CSS 中定义颜色/宽度等样式。
| selectedPane.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY))); |
| getChildren().add(0, selectedPane); | ||
| } | ||
| cellRippler.resizeRelocate(0, 0, getWidth(), getHeight()); | ||
| cellRippler.releaseRipple(); |
There was a problem hiding this comment.
layoutChildren() 每次布局都会调用 cellRippler.releaseRipple(),会导致涟漪效果在重布局/滚动时被强制结束,并带来额外动画开销。JFXRippler 已在鼠标释放事件中自动调用 releaseRipple(),建议删除这里的调用(或仅在确有需要时在特定状态变化下调用)。
| cellRippler.releaseRipple(); |
| private void updateDisplay(T item, boolean empty) { | ||
| if (item == null || empty) { | ||
| hbox = null; | ||
| setText(null); | ||
| setGraphic(null); | ||
| } else { | ||
| TreeItem<T> treeItem = getTreeItem(); | ||
| if (treeItem != null && treeItem.getGraphic() != null) { | ||
| if (item instanceof Node) { | ||
| setText(null); | ||
| if (hbox == null) { | ||
| hbox = new HBox(3); | ||
| } | ||
| hbox.getChildren().setAll(treeItem.getGraphic(), (Node) item); | ||
| setGraphic(hbox); | ||
| } else { | ||
| hbox = null; | ||
| setText(item.toString()); | ||
| setGraphic(treeItem.getGraphic()); | ||
| } | ||
| } else { | ||
| hbox = null; | ||
| if (item instanceof Node) { | ||
| setText(null); | ||
| setGraphic((Node) item); | ||
| } else { | ||
| setText(item.toString()); | ||
| setGraphic(null); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| protected void updateItem(T item, boolean empty) { | ||
| super.updateItem(item, empty); | ||
| updateDisplay(item, empty); | ||
| setMouseTransparent(item == null || empty); | ||
| } |
There was a problem hiding this comment.
这里把 item == null 当作空单元格处理(并在 updateItem 里把 cell 设为 mouseTransparent)会破坏“值为 null 但仍是有效条目”的场景:TreeView/ListView 允许集合/TreeItem 的 value 为 null,此时 empty 通常为 false,但该实现会让行无法交互且不显示 TreeItem 的 graphic。建议仅以 empty 判断是否空行,并对 item == null 的有效条目做正常渲染/交互(例如 setMouseTransparent(empty))。
| public class JFXTreeCell<T> extends TreeCell<T> { | ||
|
|
||
| protected JFXRippler cellRippler = new JFXRippler(this) { | ||
| @Override | ||
| protected Node getMask() { | ||
| Region clip = new Region(); | ||
| JFXNodeUtils.updateBackground(JFXTreeCell.this.getBackground(), clip); | ||
| double width = control.getLayoutBounds().getWidth(); | ||
| double height = control.getLayoutBounds().getHeight(); | ||
| clip.resize(width, height); | ||
| return clip; | ||
| } | ||
|
|
||
| @Override | ||
| protected void positionControl(Node control) { | ||
| // do nothing | ||
| } | ||
| }; | ||
| private HBox hbox; | ||
| private final StackPane selectedPane = new StackPane(); | ||
|
|
||
| private final InvalidationListener treeItemGraphicInvalidationListener = observable -> updateDisplay(getItem(), | ||
| isEmpty()); | ||
| private final WeakInvalidationListener weakTreeItemGraphicListener = new WeakInvalidationListener( | ||
| treeItemGraphicInvalidationListener); | ||
|
|
||
| private WeakReference<TreeItem<T>> treeItemRef; | ||
|
|
||
| public JFXTreeCell() { | ||
| selectedPane.getStyleClass().add("selection-bar"); | ||
| selectedPane.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY))); | ||
| selectedPane.setPrefWidth(3); | ||
| selectedPane.setMouseTransparent(true); | ||
| selectedProperty().addListener((o, oldVal, newVal) -> selectedPane.setVisible(newVal ? true : false)); |
There was a problem hiding this comment.
JFXTreeCell 没有像其它 JFoenix 单元格/控件那样注册默认的 style class(例如 JFXListCell 会添加 jfx-list-cell)。缺少 style class 会让样式表难以针对 TreeCell 定制。建议添加 DEFAULT_STYLE_CLASS(例如 jfx-tree-cell)并在构造/初始化时 getStyleClass().add(...)。
| /// JFXTreeView is the material design implementation of a TreeView | ||
| /// with expand/collapse animation and selection indicator. |
There was a problem hiding this comment.
类注释提到“expand/collapse animation”,但当前实现只设置了 cellFactory 和样式类,没有任何展开/收起动画相关逻辑或自定义 Skin。建议要么补齐对应实现(通常需要自定义 TreeViewSkin/TreeCell 行为),要么更新注释以避免误导 API 使用者。
| /// JFXTreeView is the material design implementation of a TreeView | |
| /// with expand/collapse animation and selection indicator. | |
| /// JFXTreeView is a material design styled TreeView control | |
| /// that uses JFXTreeCell and a custom style class. |
No description provided.