这可能是我可以在TreeItem上添加上下文菜单而不是在JavaFX中添加TreeView

时间:2013-12-19 07:53:51

标签: javafx

我是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。

2 个答案:

答案 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的答案更优雅,并且还有其他优点,如他所描述的那样。