【问题标题】:Is this possible that i can add context menu at TreeItem rather then TreeView in JavaFX这有可能我可以在 TreeItem 而不是在 JavaFX 中的 TreeView 添加上下文菜单吗
【发布时间】:2013-12-19 07:53:51
【问题描述】:

我是 JavaFX 的新手。我使用此参考制作了自定义 TreeCell:-

http://fxexperience.com/2012/05/listview-custom-cell-factories-and-context-menus/

它非常适合我。但我的情况是我不想将此上下文菜单应用于子节点。开始时只有单个 TreeItems,而在后期这些 TreeItems 有子级,因此尝试检查 isLeaf() 方法没有意义,因为在启动时 TreeItems 处于叶级但后来它们成为父级。

所以知道我该如何实现这一点。

非常感谢。

更新:
在我的项目的初始阶段,有一棵树有三个孩子(邮件服务提供商),如下所示:-

---Gmail ---雅虎 ---重新比较

在我连接这些提供者之后,它们具有以下结构:-

邮箱 |____收件箱 |____已发送 雅虎 |___收件箱 |___已发送 |___草稿 雷迪夫 |___收件箱

现在我只需要 Gmail、Yahoo 和 rediff 上的上下文菜单,而不是收件箱或已发送邮件上的上下文菜单。

我知道 setContextmenu() 方法,但它适用于 TreeView 而不适用于 TreeItem。

【问题讨论】:

  • 不清楚您想要上下文菜单的哪个位置,在树或列表的哪个位置?可以使用 .setContextMenu 在任何控件上添加一个
  • 树有多少层,你想要上下文菜单在哪一层?
  • 来一些示例代码来展示你是如何构建你的树的。
  • 嗨布赖恩,感谢您的回复,我想要树上的 ContextMenu。我同意你的观点,我们只能在一个控件上应用,比如 TreeView,但我想为 Treeitems 添加相同的上下文菜单。 .setContextMenu() 将为所有树项添加上下文菜单,但我不想为所有树项添加上下文菜单。
  • 感谢 Jurgen 的回复,最初我的树只有零级,后来它变成了一级树,正如我现在提出的问题中所示。请参阅我更新了问题详细信息。

标签: javafx


【解决方案1】:

我会让你的树项成为 TreeItem 的后代类,如 public class ProviderTreeItem extends 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();
}

}

【讨论】:

  • 感谢您的回复布赖恩,我正在尝试您的方法,并会在它对我有用时告诉您。
  • @Vikas Sharma,我阅读了另一个答案,但我忘记了菜单在 TreeCell 上。我在没有安装 java 的计算机上写了我的答案。抱歉,我会修复它,但它更复杂。
  • 谢谢。完美工作!
【解决方案2】:

一个更简单的替代方法是检查 TreeItem 的父项是否是根项。以下 sn-p 将进入您的 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 )
    .
    .
}

虽然这更简单,但我认为布赖恩的回答更优雅,并且还具有他所描述的其他优点。

【讨论】:

  • 我同意你的观点,但在初始阶段 Gmail、Yahoo、Rediff 不是父级,在这种情况下,上下文菜单不会添加到这些 TreeItems 中,我想要这些 TreeItems 上的上下文菜单。还有一件事是我看不到任何 TreeItem 的方法 setContextMenu。它仅适用于 TreeView。我也在尝试 Mr. Brain 方法,感谢 Jurgen 的帮助。请继续帮助我,直到我解决这个问题。
  • 其实我理解你说的,我认为你是对的..给我时间试一试。
  • 只是为了清楚代码的 sn-p 是为您的 TreeCell 而不是 TreeItem。
【解决方案3】:

这是我最喜欢的用于在TreeView 中定义 cellFactory 的实用方法。一是设置TreeCell转换为String,二是应用ContextMenu

public static <T> void setCellFactory(TreeView<T> treeView,
                                      ToStringConverter<T> converter,
                                      ContextMenu contextMenu) {

treeView.setCellFactory(tc -> {

  TreeCell<T> cell = new TreeCell<T>() {

    @Override
    protected void updateItem(T item, boolean empty) {
      super.updateItem(item, empty);
      if (empty) {
        setText(null);
      } else {
        setText(converter.toString(item));
      }
    }

  };

  cell.emptyProperty()
      .addListener((obs, wasEmpty, isNowEmpty) -> {
        if (isNowEmpty) {
          cell.setContextMenu(null);
        } else {
          cell.setContextMenu(contextMenu);
        }
      });

  return cell;

  });

}

ToStringCoverter是接口

public interface ToStringConverter<T> {
  String toString(T t);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    相关资源
    最近更新 更多