How to prevent TableView from doing TableColumn re-order in javaFX 8?

An alternative solution which does not require use of private API in Java 8.

public static <T> void preventColumnReordering(TableView<T> tableView) {
    Platform.runLater(() -> {
        for (Node header : tableView.lookupAll(".column-header")) {
            header.addEventFilter(MouseEvent.MOUSE_DRAGGED, Event::consume);
        }
    });
}

I know the question tagged java-8 but for those who wander along, In Java 9 all above codes would break because of modularity which make .sun package inaccessible and removal of impl_. Despite these changes, it introduces convenient public methods that you can use which are:

  • setReorderable(boolean value)
  • getReorderable()

for TableColumnBase such as TableColumn to be used for set Reorderable,


Spent half of a day trying to solve the problem. Maybe my investigation can be useful for someone else. It's possible to disable column reordering using some hacks. And here're the steps:

  1. Get table header. This can be done as described here: https://stackoverflow.com/a/12465155
  2. Add change event listener to reorderingProperty which sets reordering back to false.

Full code is here:

tableView.widthProperty().addListener(new ChangeListener<Number>()
{
    @Override
    public void changed(ObservableValue<? extends Number> source, Number oldWidth, Number newWidth)
    {
        TableHeaderRow header = (TableHeaderRow) tableView.lookup("TableHeaderRow");
        header.reorderingProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                header.setReordering(false);
            }
        });
    }
});

I'm not sure about side effects of this solution, but quick tests show that solution works well.


I like the idea from Alexander Chingarev but I think the code will produce memory leaks! Every time the width property changes a new listener is registered and older listeners are never garbage collected! So you can either store a reference to the listener and make sure to remove it from the observable value (in this case the reordering property) before adding a new listener or you make sure the listener is only added once to the reordering property.

I used the skin property which only changes once (if I'm not mistaken) to add my listener:

tableView.skinProperty().addListener((obs, oldSkin, newSkin) -> {
    final TableHeaderRow header = (TableHeaderRow) lookup("TableHeaderRow");
    header.reorderingProperty().addListener((o, oldVal, newVal) -> header.setReordering(false));
});