TUYÊN BỐ TỪ CHỐI: Đây không phải là giải pháp thích hợp, nó là xấu xí, không được kiểm tra tốt và có nhiều hạn chế (xem bên dưới). Ngoài ra nó có thể sẽ phá vỡ với bản phát hành Java tiếp theo, NHƯNG nó giải quyết được vấn đề trong trường hợp vani trơn chuẩn của tôi vì vậy tôi quyết định chia sẻ nó chỉ trong trường hợp ai đó có thể thấy nó hữu ích. Sử dụng nó rủi ro của riêng bạn! :)
Tôi cũng có một hy vọng nhỏ rằng ai đó có kiến thức tốt hơn về API skin JavaFX có thể cải thiện nó, tôi sẽ đánh giá cao!
Những hạn chế:
- Chỉ làm việc cho
ContextMenu
, không phải với menu chính (đây là trường hợp sử dụng của tôi)
- Chỉ làm việc cho các menu một cấp (không thể tìm ra cách để mở rộng cho menu con)
- Không chắc chắn nếu nó hoạt động với
CustomMenuItem
s hoặc với MenuItem
s với số Graphic
, nhưng có thể!
- Nó dựa trên tiêu chuẩn
ContextMenuContent
làm da cho ContextMenu
. Nếu bạn có làn da của riêng bạn thì nó sẽ không hoạt động.
Đây là lớp helper:
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();
});
});
}
}
Cách sử dụng rất đơn giản:
ContextMenuFixer.fix(myContextMenu);
T.B. Một giải pháp sạch sẽ là viết lớp da thích hợp của riêng bạn (tức là, để thay thế ContextMenuContent
) nhưng tôi cố ý không muốn đi theo cách đó vì chi phí bảo trì.
Có thể gửi một [báo cáo lỗi] (https://javafx-jira.kenai.com) về việc này. – jewelsea
Ai đó có thể nộp nó không? Tôi hoàn toàn không quen thuộc với nền tảng đó. – Voldemort
Đã xảy ra sự cố đã biết, được báo cáo [tại đây] (https://javafx-jira.kenai.com/browse/RT-22442) – crusam