我是JavaFX的新手。我使用这个引用创建了自定义TreeCell: -
http://fxexperience.com/2012/05/listview-custom-cell-factories-and-context-menus/
它对我很有用。但我的情况是我不想将此上下文菜单应用于子节点。在开始时,只有一个TreeItems,并且在稍后阶段这些TreeItems具有子项,因此尝试检查isLeaf()方法没有意义,因为在启动时TreeItems处于叶级但后来它们变为父级。
所以我知道如何实现这一目标。
非常感谢。
更新
在我的项目的初始阶段,有一个有三个孩子的树(邮件服务提供商)如下: -
---Gmail ---Yahoo ---Rediff
在我连接这些提供者后,他们就有了这种结构: -
Gmail |____Inbox |____Sent Yahoo |___Inbox |___Sent |___Drafts Rediff |___Inbox
现在我只想在Gmail,Yahoo和rediff上使用上下文菜单,而不是收件箱或已发送项目。
我知道setContextmenu()方法,但这适用于TreeView而不适用于TreeItem。
答案 0 :(得分:5)
我会使你的树项成为像public class ProviderTreeItem extends TreeItem
这样的TreeItem的后代类,以及像BoxTreeItem这样的框的不同后代。
这样你就不会测试isLeaf,但你可以测试TreeItem类型。
if (thisTreeItem.getClass() == ProviderTreeItem.class)
thisTreeItem.setContextmenu(providerContextMenu)
else thisTreeItem.setContextmenu(boxContextMenu)
从子类TreeItem中获取上下文菜单会更容易。
您不需要继承TreeItem的子类,您可以使用名称或类似userData对象的东西来区分节点类型。如果是子类,则可以向不同的节点类型添加不同的方法和属性。
例如,这些框需要一个数据结构来保存电子邮件,但提供者不需要这样。提供商需要一个网址和密码等,但这些框不需要。
以下是更新后的示例。
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TVexample extends Application {
public abstract class AbstractTreeItem extends TreeItem{
public abstract ContextMenu getMenu();
}
public class ProviderTreeItem extends AbstractTreeItem{
// make class vars here like psswd
public ProviderTreeItem(String name) {
this.setValue(name);
}
@Override
public ContextMenu getMenu(){
MenuItem addInbox = new MenuItem("add inbox");
addInbox.setOnAction(new EventHandler() {
public void handle(Event t) {
BoxTreeItem newBox = new BoxTreeItem("inbox");
getChildren().add(newBox);
}
});
return new ContextMenu(addInbox);
}
}
public class BoxTreeItem extends AbstractTreeItem{
//private List<String> emails = new LinkedList<>();
public BoxTreeItem(String name) {
this.setValue(name);
}
@Override
public ContextMenu getMenu() {
return new ContextMenu(new MenuItem("test"));
}
}
private final class TreeCellImpl extends TreeCell<String> {
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
setText(getItem() == null ? "" : getItem().toString());
setGraphic(getTreeItem().getGraphic());
setContextMenu(((AbstractTreeItem) getTreeItem()).getMenu());
}
}
}
@Override
public void start(Stage primaryStage) {
StackPane sceneRoot = new StackPane();
TreeItem treeRoot = new TreeItem();
treeRoot.setExpanded(true);
ProviderTreeItem gm = new ProviderTreeItem("gmail");
ProviderTreeItem yh = new ProviderTreeItem("yahoo");
treeRoot.getChildren().addAll(gm,yh);
TreeView<String> treeView = new TreeView<String>(treeRoot);
treeView.setShowRoot(false);
treeView.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>(){
@Override
public TreeCell<String> call(TreeView<String> p) {
return new TreeCellImpl();
}
});
sceneRoot.getChildren().add(treeView);
Scene scene = new Scene(sceneRoot, 300, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
}
答案 1 :(得分:0)
更简单的替代方法是检查TreeItem的父级是否是根项。以下代码片段将放在您的TreeCell中:
public void updateItem( Object item, boolean empty )
{
super( item, empty );
TreeItem thisTreeItem = getTreeItem();
if ( thisTreeItem.getParent() == rootItem )
thisTreeItem.setContextmenu( providerContextMenu )
else thisTreeItem.setContextmenu( boxContextMenu )
.
.
}
虽然这更简单,但我认为Brian的答案更优雅,并且还有其他优点,如他所描述的那样。