Disable TreeItem's default expand/collapse on

2019-01-26 16:44发布

I am working on a JavaFX 2.2 project and i want to set custom handling of the mouse (double) click event on a TreeItem. Using treeview.setOnMouseClicked i fire my code without errors but the problem is that the TreeItem, on every mouse double click, it toggles between expanded and collapsed. I suppose that this is the default behavior, but how i disable it??

2条回答
做个烂人
2楼-- · 2019-01-26 17:07

Turns out that though Bolg's answer works, it isn't strictly the "correct" way to do it, and may cause some unexpected behaviour.

The cause of this issue is described in this bug. To summarise: the default double click behaviour of a tree cell is actually precipitated by the mouse press event, so it's too late to consume the event and block it within a mouse click listener.

The reason the accepted answer works is that it doesn't filter on the mouse event type, meaning it consumes all mouse events relating to the primary button and a click count of two. This also means that the user action is processed three times, which is probably not the intended behaviour.

The fix is only a single line change to Bolg's answer, but I think it is probably better not to involve an EventDispatcher. Something like the following should work just fine:

node.addEventHandler(MouseEvent.ANY, event -> {
    if (event.getClickCount() == 2 && event.getButton().equals(MouseButton.PRIMARY)) {
        if (event.getEventType().equals(MouseEvent.MOUSE_CLICKED)) {
            System.out.println("hello"); // perform some action
        }

        event.consume();
    }
});
查看更多
在下西门庆
3楼-- · 2019-01-26 17:28

I had the same issue and solved it in time using EventDispatcher.

class TreeMouseEventDispatcher implements EventDispatcher {
    private final EventDispatcher originalDispatcher;

    public TreeMouseEventDispatcher(EventDispatcher originalDispatcher) {
      this.originalDispatcher = originalDispatcher;
    }

    @Override
    public Event dispatchEvent(Event event, EventDispatchChain tail) {
        if (event instanceof MouseEvent) {
           if (((MouseEvent) event).getButton() == MouseButton.PRIMARY
               && ((MouseEvent) event).getClickCount() >= 2) {

             if (!event.isConsumed()) {
               // Implement your double-click behavior here, even your
               // MouseEvent handlers will be ignored, i.e., the event consumed!
             }

             event.consume();
           }
        }
        return originalDispatcher.dispatchEvent(event, tail);
    }
}

and then use this TreeMouseEventDispatcher for the TreeCell:

treeView.setCellFactory(new Callback<TreeView<T>, TreeCell<T>>() {
  @Override
  public TreeCell<T> call(TreeView<T> param) {
    return new TreeCell<T>() {
      @Override
      protected void updateItem(T item, boolean empty) {
        if (item != null && !empty) {
          EventDispatcher originalDispatcher = getEventDispatcher();
          setEventDispatcher(new TreeMouseEventDispatcher(originalDispatcher));
        }
      }
    };
  }
}
查看更多
登录 后发表回答