好的,我找到了以下(非常非常脏)的解决方法。我以前从未尝试过,因为我认为它会阻止上下文菜单显示(正如我在原始问题中指出的那样),但显然只是简单地消耗了每个TableColumnHeader
作品的鼠标事件并且上下文菜单仍然正确显示(也适用于没有 TableColumns上下文菜单)。
不确定内部是否会出现任何问题,但由于默认情况下右键单击似乎没有做任何有用的事情,我希望不会。
当然lookupAll
需要在渲染后调用。
注意 1:如果您已TableMenuButtonVisible
设置为 true,则每次将列设置为可见时都需要执行此操作。
注2:它越来越脏。在将列设置为可见后再次调用它(见注 1)并不总是足够的(也不能通过Platform.runLater
调用)。我认为那是因为此时尚未呈现列标题。你要么
- 需要等到
Set<Node>
完全填满,即它的大小必须是amountOfVisibleColumns + 1
。如果它等于可见列的数量,它将不适用于新显示的列。
- 或之前调用
layout()
TableViewlookupAll
- 或者如果你有一个扩展类
TableView
,覆盖layoutChildren
并执行查找,如果可见列的数量发生了变化
注意3onMousePressed
:如果按钮不是,您需要跟踪旧的并执行它SECONDARY
,否则列的重新排序将不起作用。
如果您能想到任何更清洁的方法,请告诉我。

import java.util.Set;
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.skin.TableColumnHeader;
import javafx.scene.input.MouseButton;
import javafx.stage.Stage;
public class Foo extends Application {
@Override
public void start(Stage stage) throws Exception {
TableView<Object> testView = new TableView<>();
testView.getColumns().addAll(createColumn("C1"), createColumn("C2"), createColumn("C3"));
stage.setOnShown(ev -> {
Set<Node> headers = testView.lookupAll("TableColumnHeader");
for (Node header : headers) {
if (header != null) {
((TableColumnHeader) header).setOnMousePressed(e -> {
if (e.getButton() == MouseButton.SECONDARY) {
e.consume();
}
});
}
}
});
stage.setScene(new Scene(testView));
stage.show();
}
private TableColumn<Object, Object> createColumn(String text) {
MenuItem item = new MenuItem("Context");
item.setOnAction(e -> {
System.out.println("Action");
});
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().add(item);
TableColumn<Object, Object> column = new TableColumn<>(text);
column.setContextMenu(contextMenu);
return column;
}
public static void main(String[] args) {
launch(args);
}
}