TreeView/TreeTableView-KeyEvent F2导致JavaFX内部NPE [英] TreeView/TreeTableView - KeyEvent F2 causes JavaFX internal NPE

查看:107
本文介绍了TreeView/TreeTableView-KeyEvent F2导致JavaFX内部NPE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过执行以下操作,在TreeTableView的第0列上放置了标准"编辑器:

Having put a "standard" editor on column 0 of a TreeTableView by doing this:

treeTableView.columns.get(0).setCellFactory( TextFieldTreeTableCell.forTreeTableColumn());

...很高兴发现有几件事开始编辑TreeItem:一种是单击单元格,另一种是按F2键.

... it's nice to find that a couple of things start an edit of a TreeItem: one is to click the cell, and another is to press F2.

但是,令我有些沮丧的是,如果我启动该应用程序,并且没有使用鼠标选择TreeItem,而是以编程方式选择了根TreeItem的第一个孩子,那么我(可能在导航后)仅使用键盘键)按F2键,JavaFX内部构件会抛出一个NPE,如下所示:

To my slight dismay, however, if I start up the app and, without having selected a TreeItem using the mouse, but having programmatically selected the first child of the root TreeItem, if I then (possibly after navigating using keyboard keys only) press F2, the JavaFX internals throw an NPE, which looks like this:

java.lang.NullPointerException: null
    at com.sun.javafx.scene.control.behavior.TableViewBehaviorBase.activate(TableViewBehaviorBase.java:890)
    at com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$KeyHandler.process(Scene.java:4058)
    at javafx.scene.Scene$KeyHandler.access$1500(Scene.java:4004)
    at javafx.scene.Scene.processKeyEvent(Scene.java:2121)
    at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2595)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:217)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:149)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent$1(GlassViewEventHandler.java:248)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:390)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:247)
    at com.sun.glass.ui.View.handleKeyEvent(View.java:547)
    at com.sun.glass.ui.View.notifyKey(View.java:971)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)

不可能是鼠标将焦点直接放在TreeItem上,因为TreeItem的超类是Object.我在Scene上放置了一个焦点所有者侦听器,该监听器确认单击TreeTableView时没有与焦点相关的更改.但是,从本质上讲,某些事情确实发生了变化.

It can't be that the mouse puts the focus directly on the TreeItem because TreeItem's super class is Object. I put a focus owner listener on the Scene, which confirms that nothing focus-related changes when you click on the TreeTableView. And yet, qualitatively, something does change.

也许与BehaviorInputMap,皮肤"或我不了解的许多神秘的JavaFX事物中的任何一个有关.

Maybe it's something to do with Behavior, InputMap, "skins", or any one of many mysterious JavaFX things of which I am ignorant.

在这种情况下,在我看来,一种选择可能是以某种方式截获F2按键并阻止默认功能,并以编程方式激发选择但不具有焦点的TreeItem的编辑.

Under these circumstances, it seems to me that one option might be to intercept the F2 keystroke somehow, and prevent the default functioning, and also programmatically instigate editing of the TreeItem which is selected but which doesn't have focus.

注意,我在TreeTableView上放置了按下键"和释放键"事件侦听器.其中包括以下行:

NB I put a "key pressed" and "key released" event listeners on the TreeTableView. These included the following line:

TreeTablePosition pos = treeTableView.getFocusModel().getFocusedCell();

我描述的异常"事件是JavaFX内部在其中抛出NPE的事件,其特征在于键释放"侦听器中的pos.col == -1pos.getTableColumn() == null.从日志记录中,我还可以看出NPE发生在密钥释放"处理程序响应之前.

The "anomalous" event I'm describing, where the JavaFX internals throw an NPE, is characterised by, in the "key release" listener, pos.col == -1 and pos.getTableColumn() == null. I can also tell, from logging, that the NPE happens before the "key released" handler responds.

有关信息,当我按F2时,如果没有先单击鼠标c TreeItem,按键"监听器就不会记录任何内容(毫无疑问,这是因为JavaFX内部的Exception杀死了正常的广播"监听器) ,让我假设JavaFX框架也位于任何用户添加的按键侦听器之前.

For information, the "key pressed" listener never logs anything when I press F2 without having first mouse-clicked a TreeItem (due no doubt to the JavaFX internal Exception killing off the normal "broadcast" to listeners), leading me to suppose that the JavaFX framework also precedes any user-added key-press listener.

推荐答案

如果使用

If you select your cell using TableSelectionModel#select(int,TableColumnBase) then the NPE does not occur.

选择给定行/列相交处的单元格.如果表控件处于单元格选择"模式(可以选择单个单元格,而不是整个行),并且column参数为null,则此方法应选择给定行中的所有单元格.

Selects the cell at the given row/column intersection. If the table control is in its 'cell selection' mode (where individual cells can be selected, rather than entire rows), and if the column argument is null, this method should select all cells in the given row.

例如:

TreeTableColumn col = treeTableView.getColumns().get(0);
treeTableView.getSelectionModel().select(rowIndex, col);

有了上面的内容,您不必担心焦点模型.这样做的原因是因为默认的选择模型实现将为您重点关注给定的行+列(即单元格)(不确定这是否是保证的行为,但肯定是礼貌的行为).

With the above you don't have to worry about the focus model. The reason for that is because the default selection model implementation will focus the given row+column (i.e. cell) for you (not sure if that's guaranteed behavior but it's certainly polite behavior).

基本上,您当前的代码导致一行被选中/集中显示,而不是该行中的特定单元格.因此,当您尝试进入编辑模式"时,无法确定要定位的单元格.我认为NPE是一个错误.不知道在没有选择/集中选择任何列时会发生什么 meant ,但是控件的行为应该适当地处理这种情况.

Basically, your current code caused a row to be selected/focused but not a specific cell in that row. Thus when you tried to enter "edit mode" there was no way to determine which cell to target. I would consider the NPE to be a bug. Not sure what's meant to happen when no column is selected/focused, but the control's behavior should handle that case gracefully.

如果有兴趣,下面是我的调试过程.

If interested, below was my debugging process.

以下是负责NPE的代码:

Here's the code responsible for the NPE:

protected void activate(KeyEvent e) {
    TableSelectionModel sm = getSelectionModel();
    if (sm == null) return;

    TableFocusModel fm = getFocusModel();
    if (fm == null) return;

    TablePositionBase<TC> cell = getFocusedCell();
    sm.select(cell.getRow(), cell.getTableColumn());
    setAnchor(cell);

    // check if we are editable
    boolean isEditable = isControlEditable() && cell.getTableColumn().isEditable();

    // edit this row also
    if (isEditable && cell.getRow() >= 0) {
        editCell(cell.getRow(), cell.getTableColumn());
        e.consume();
    }
}

具体来说,这是有问题的行:

Specifically, this is the problematic line:

boolean isEditable = isControlEditable() && cell.getTableColumn().isEditable();

这意味着cell为null或getTableColumn()返回null.在 JEP 358:有用的NullPointerExceptions 的帮助下进行调试后,我们知道是后者:

Which means either cell is null or getTableColumn() is returning null. After some debugging with the help of JEP 358: Helpful NullPointerExceptions we know it's the latter:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException: Cannot invoke "javafx.scene.control.TableColumnBase.isEditable()" because the return value of "javafx.scene.control.TablePositionBase.getTableColumn()" is null
    at javafx.controls/com.sun.javafx.scene.control.behavior.TableViewBehaviorBase.activate(TableViewBehaviorBase.java:898)

如果getTableColumn()返回null,则意味着就焦点模型而言,没有列被聚焦,因此没有特定单元格被聚焦.解决方法是选择/聚焦特定的行+列(即单元格),而不仅仅是整个行.

If getTableColumn() is returning null then that means that, as far as the focus model is concerned, there is no column focused and thus no specific cell is focused. The fix is to select/focus a specific row+column (i.e. cell) and not just an entire row.

这篇关于TreeView/TreeTableView-KeyEvent F2导致JavaFX内部NPE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆