[基本上,我想知道是否可以创建树并在javaFX上对其进行自定义...我尝试这样做,但是到目前为止,使用此代码无法执行任何操作...
public class Main{
......
public Main() throws Exception{
......
// TreeView created
TreeView tv = (TreeView) fxmlLoader.getNamespace().get("treeview");
TreeItem<String> rootItem = new TreeItem<String>("liss");
rootItem.setExpanded(true);
tv.setRoot(rootItem);
/*for (int i = 1; i < 6; i++) {
TreeItem<String> item = new TreeItem<String> ("Message" + i);
rootItem.getChildren().add(item);
}
TreeItem<String> item = new TreeItem<String> ("MessageWoot");
rootItem.getChildren().add(item);
*/
//tv.setEditable(true);
tv.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
@Override
public TreeCell<String> call(TreeView<String> arg0) {
// custom tree cell that defines a context menu for the root tree item
return new MyTreeCell();
}
});
stage.show();
}
//
private static class MyTreeCell extends TextFieldTreeCell<String> {
private ContextMenu addMenu = new ContextMenu();
public boolean clickedFirstTime = false;
public MyTreeCell() {
// instantiate the root context menu
MenuItem addMenuItem = new MenuItem("Expand");
addMenu.getItems().add(addMenuItem);
addMenuItem.setOnAction(new EventHandler() {
public void handle(Event t) {
TreeItem n0 =
new TreeItem<String>("'program'");
TreeItem n1 =
new TreeItem<String>("<identifier>");
TreeItem n2 =
new TreeItem<String>("body");
getTreeItem().getChildren().add(n0);
getTreeItem().getChildren().add(n1);
getTreeItem().getChildren().add(n2);
}
});
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
// if the item is not empty and is a root...
//if (!empty && getTreeItem().getParent() == null && this.clickedFirstTime) {
System.out.println("UPDATEITEM -> clickedFirstTime : "+this.clickedFirstTime);
if (!this.clickedFirstTime) {
System.out.println("WOOT");
setContextMenu(addMenu);
this.clickedFirstTime = true;
}
}
}
而且我在问自己这是否是正确的“技术”,它将解决我正在尝试做的事情...
我的目标是什么?
首先,我正在寻找添加或删除treeItem。我必须说,某个treeItem只能添加一次或任意N次,例如,限制(例如:treeItem <6对于特定级别的作用域和树视图根的特定路径)。
第二,使某些treeItem可编辑,而另一些则不可编辑!当它为“可编辑”时,您可以为用户弹出一些内容以例如插入一些输入!
有可能吗?
我看过https://docs.oracle.com/javafx/2/ui_controls/tree-view.htm#BABJGGGF中的教程,但是我对此教程感到非常困惑...我不太了解单元工厂机制...当我只想要某个TreeItem时,他确实适用于TreeView的事实...或者我该如何控制这种效果/行为?我的意思是,我真的很迷上TreeView。也许,TreeView不是我想要的...
P.S .:我知道我无法应用任何视觉效果或向树项添加菜单,并且我使用单元工厂机制来克服此障碍。只是我不明白这个主意,我该怎么做!
如果要使用JavaFX,请确保这是正确的“技术”。但是,您可能应该对TreeItem
使用更复杂的类型参数。您可以使用自定义TreeCell
允许所需的用户交互。
此示例允许通过上下文菜单添加子节点和删除节点(除非内容为"nocontext"
)以及编辑内容(只要内容不是"noedit"
);在根节点上,delete选项被禁用:
tv.setEditable(true);
tv.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
private final MyContextMenu contextMenu = new MyContextMenu();
private final StringConverter converter = new DefaultStringConverter();
@Override
public TreeCell<String> call(TreeView<String> param) {
return new CustomTreeCell(contextMenu, converter);
}
});
public class CustomTreeCell extends TextFieldTreeCell<String> {
private final MyContextMenu contextMenu;
public CustomTreeCell(MyContextMenu contextMenu, StringConverter<String> converter) {
super(converter);
if (contextMenu == null) {
throw new NullPointerException();
}
this.contextMenu = contextMenu;
this.setOnContextMenuRequested(evt -> {
prepareContextMenu(getTreeItem());
evt.consume();
});
}
private void prepareContextMenu(TreeItem<String> item) {
MenuItem delete = contextMenu.getDelete();
boolean root = item.getParent() == null;
if (!root) {
delete.setOnAction(evt -> {
item.getParent().getChildren().remove(item);
contextMenu.freeActionListeners();
});
}
delete.setDisable(root);
contextMenu.getAdd().setOnAction(evt -> {
item.getChildren().add(new TreeItem<>("new item"));
contextMenu.freeActionListeners();
});
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
setContextMenu("nocontext".equals(item) ? null : contextMenu.getContextMenu());
setEditable(!"noedit".equals(item));
}
}
}
public class MyContextMenu {
private final ContextMenu contextMenu;
private final MenuItem add;
private final MenuItem delete;
public MyContextMenu() {
this.add = new MenuItem("add child");
this.delete = new MenuItem("delete");
this.contextMenu = new ContextMenu(add, delete);
}
public ContextMenu getContextMenu() {
return contextMenu;
}
public MenuItem getAdd() {
return add;
}
public MenuItem getDelete() {
return delete;
}
/**
* This method prevents memory leak by setting all actionListeners to null.
*/
public void freeActionListeners() {
this.add.setOnAction(null);
this.delete.setOnAction(null);
}
}
当然可以在updateItem
和prepareContextMenu
中进行更复杂的检查,并且可以支持不同的用户交互(TextFieldTreeCell
可能不是适合您的超类;您可以使用“普通” TreeCell
和当用户在上下文菜单中选择MenuItem
时,显示另一个阶段/对话框来编辑项目。
单元格工厂用于在显示数据的类中创建单元格(例如TableColumn
,TreeView
,ListView
)。当此类需要显示内容时,它将使用其单元工厂来创建用于显示数据的Cell
。在这样的单元格中显示的内容可能会更改(请参见updateItem
方法)。
(我不是100%肯定这是正确的方法,但是应该足够接近)
创建一个updateItem
以显示具有2个非扩展子级的扩展根节点。
TreeView
确定需要为根节点显示3个项目,它是2个子节点。因此,TreeView
使用它的单元格工厂来创建3个单元格,并将它们添加到其布局中并分配显示的项目。
现在,用户展开第一个孩子,该孩子拥有两个孩子。 TreeView
确定还需要2个单元格才能显示项目。为了提高效率,在布局的末尾添加了新的单元格,并更新了单元格的项目:
因此,我决定取消TreeView(因为文档太垃圾了……),而是决定实现一个Webview!
为什么?
类似,我可以创建一个HTML文档并在其中使用jstree(jquery插件-TreeView
)。这是一个将基本创建树视图的插件。
不幸的是,该文档比treeview oracle文档好十倍。
而且,使用jstree创建/编辑树的可能性更好。得出的结论是,这是我可以为我找到的最佳解决方案。
[此外,无论谁愿意读我,我都与webview和javafx应用程序架起了桥梁!它是我的HTML文档和Java应用程序之间的连接(在此处了解更多信息-https://www.jstree.com)。
希望它将帮助更多的人。