A cell contextMenu can't be activated by keyboard:它的根本原因是contextMenuEvent被調度到焦點節點 - 這是包含表格,而不是單元格。喬納森的錯誤評估對如何解決它的輪廓:單元格:如何通過鍵盤激活contextMenu?
的「正確」的方式做到這一點是可能覆蓋TableView中的buildEventDispatchChain和包括TableViewSkin(如果它實現了此事件),並隨時轉發這下降到表格行中的單元格。
試圖遵循該路徑(下面是ListView的一個例子,只是因爲只有一個級別的皮膚來實現兩個TableView)。它正在工作,種類:單元格contextMenu由鍵盤彈出式觸發器激活,但相對於表格相對於單元格定位。
問題:如何掛鉤到調度鏈中,使其位於相對於單元?
可運行的代碼示例:
package de.swingempire.fx.scene.control.et;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventDispatchChain;
import javafx.event.EventTarget;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Cell;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Skin;
import javafx.stage.Stage;
import com.sun.javafx.event.EventHandlerManager;
import com.sun.javafx.scene.control.skin.ListViewSkin;
/**
* Activate cell contextMenu by keyboard, quick shot on ListView
* @author Jeanette Winzenburg, Berlin
*/
public class ListViewETContextMenu extends Application {
private Parent getContent() {
ObservableList<String> data = FXCollections.observableArrayList("one", "two", "three");
// ListView<String> listView = new ListView<>();
ListViewC<String> listView = new ListViewC<>();
listView.setItems(data);
listView.setCellFactory(p -> new ListCellC<>(new ContextMenu(new MenuItem("item"))));
return listView;
}
/**
* ListViewSkin that implements EventTarget and
* hooks the focused cell into the event dispatch chain
*/
private static class ListViewCSkin<T> extends ListViewSkin<T> implements EventTarget {
private EventHandlerManager eventHandlerManager = new EventHandlerManager(this);
@Override
public EventDispatchChain buildEventDispatchChain(
EventDispatchChain tail) {
int focused = getSkinnable().getFocusModel().getFocusedIndex();
if (focused > - 1) {
Cell<?> cell = flow.getCell(focused);
tail = cell.buildEventDispatchChain(tail);
}
// returning the chain as is or prepend our
// eventhandlermanager doesn't make a difference
// return tail;
return tail.prepend(eventHandlerManager);
}
// boiler-plate constructor
public ListViewCSkin(ListView<T> listView) {
super(listView);
}
}
/**
* ListView that hooks its skin into the event dispatch chain.
*/
private static class ListViewC<T> extends ListView<T> {
@Override
public EventDispatchChain buildEventDispatchChain(
EventDispatchChain tail) {
if (getSkin() instanceof EventTarget) {
tail = ((EventTarget) getSkin()).buildEventDispatchChain(tail);
}
return super.buildEventDispatchChain(tail);
}
@Override
protected Skin<?> createDefaultSkin() {
return new ListViewCSkin<>(this);
}
}
private static class ListCellC<T> extends ListCell<T> {
public ListCellC(ContextMenu menu) {
setContextMenu(menu);
}
// boiler-plate: copy of default implementation
@Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else if (item instanceof Node) {
setText(null);
Node currentNode = getGraphic();
Node newNode = (Node) item;
if (currentNode == null || ! currentNode.equals(newNode)) {
setGraphic(newNode);
}
} else {
/**
* This label is used if the item associated with this cell is to be
* represented as a String. While we will lazily instantiate it
* we never clear it, being more afraid of object churn than a minor
* "leak" (which will not become a "major" leak).
*/
setText(item == null ? "null" : item.toString());
setGraphic(null);
}
}
}
@Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(getContent());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
入住這裏,http://stackoverflow.com/a/23420064/2855515 – brian 2015-02-23 13:29:16
@布賴恩是的,所見到的 - 感謝參考反正:-)但黑客(另一個是跟蹤的該顯示屬性contextMenu並手動定位)不是我所追求的 - 我想掛鉤到事件調度中,以便默認的顯示/定位在沒有進一步努力的情況下在部分客戶端代碼上工作 – kleopatra 2015-02-23 13:59:53