如果您按住鼠标单击其中一个 MenuItem,然后拖动鼠标离开,该按钮将保持选中状态。即使将鼠标拖动到 New
或 Save
,Open
按钮仍将保持选中状态。如果您在 Open
之外的任何地方释放鼠标,该命令将仍然执行。换句话说,在您按住鼠标的那一刻,即将调用 Open
的 onAction()
。
这与 Mac OSX 中的正常行为不同,我猜也与 Windows native 应用程序不同。在它们中,即使您按住菜单项上的点击,如果您将鼠标移开,按钮也不会触发。但它确实发生在 JavaFX 中。
我该怎么做才能解决这个问题? JavaFX 8。
最佳答案
免责声明:这不是一个合适的解决方案,它很丑陋,没有经过充分测试,并且有很多限制(见下文)。它也可能会随着下一个 Java 版本的发布而中断,但是它解决了我非常标准的普通 Vanilla 案例中的问题,所以我决定分享它以防万一有人发现它有用。使用它你自己的风险! :)
我也希望对 JavaFX 皮肤 API 有更好了解的人可以改进它,我将不胜感激!
限制:
- 仅适用于
ContextMenu
,不适用于主菜单(这是我的用例) - 仅适用于一级菜单(不知道如何扩展子菜单)
- 不确定它是否与
CustomMenuItem
一起使用,或者与带有Graphic
的MenuItem
一起使用,但它可能! - 它依赖于标准的
ContextMenuContent
作为ContextMenu
的外观。如果您有自己的皮肤,那么它将不起作用。
这是辅助类:
public class ContextMenuFixer {
public static void fix(ContextMenu contextMenu) {
if (contextMenu.getSkin() != null) {
fix(contextMenu, (ContextMenuContent) contextMenu.getSkin().getNode());
} else {
contextMenu.skinProperty().addListener((observable, oldValue, newValue) -> {
if(newValue != null) {
fix(contextMenu, (ContextMenuContent) contextMenu.getSkin().getNode());
}
});
}
}
private static void fix(ContextMenu menu, ContextMenuContent content) {
content.getItemsContainer().getChildren().forEach(node -> {
EventHandler<? super MouseEvent> releaseEventFilter = event -> {
if (!((Node) event.getTarget()).isFocused()) {
event.consume();
menu.hide();
}
};
node.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
node.removeEventFilter(MouseEvent.MOUSE_RELEASED, releaseEventFilter);
});
node.addEventHandler(MouseEvent.DRAG_DETECTED, event -> {
node.startFullDrag();
node.addEventFilter(MouseEvent.MOUSE_RELEASED, releaseEventFilter);
});
node.addEventHandler(MouseDragEvent.MOUSE_DRAG_ENTERED, event -> {
MouseEvent e = event.copyFor(event.getSource(), event.getTarget(), MouseEvent.MOUSE_ENTERED);
node.fireEvent(e);
});
node.addEventHandler(MouseDragEvent.MOUSE_DRAG_RELEASED, event -> {
Event e = event.copyFor(event.getSource(), event.getTarget(), MouseEvent.MOUSE_RELEASED);
node.fireEvent(e);
});
node.addEventHandler(MouseDragEvent.MOUSE_DRAG_EXITED, event -> {
node.getParent().requestFocus();
});
node.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> {
menu.hide();
});
});
}
用法非常简单:
ContextMenuFixer.fix(myContextMenu);
附言一个更简洁的解决方案是编写您自己的适当皮肤类(即替换 ContextMenuContent
),但由于维护成本,我故意不想这样做。
关于无法通过将鼠标移开来取消 JavaFX MenuItem,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29283426/