JavaFX: Right click on TableColumn disables resizing

Lukas Rotter :

Reproduced in OpenJFX 11.0.2 & 12.0.1 SDK (Windows 10, x64), not reproducible in JavaFX 8

Right-click on a table-column, then try to resize the column. No resize cursor is shown and column can't be resized until you manually click on the column again.

Any ideas for a workaround? I need to usecontextMenu for TableColumns, so potential workarounds that make the header ignore right mouse click aren't possible.

enter image description here

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
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(new TableColumn<Object, Object>("C1"), new TableColumn<Object, Object>("C2"), new TableColumn<Object, Object>("C3"));

        stage.setScene(new Scene(testView));
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Lukas Rotter :

Ok I found the following (very, very dirty) workaround. I never tried this before because I assumend it would prevent the context menu from showing (as I noted in my original question), but apprently simply consuming the mouse event of every TableColumnHeader works and the context menu is still shown correctly (also works with TableColumns without context menus).

Not sure if anything internal could go wrong with this, but as the right click doesn't seem to be doing anything useful by default, I hope not.

Of course lookupAll needs to be called after it has been rendered.

Note 1: If you have TableMenuButtonVisible set to true, you need to do this every time a column is set to visible.

Note 2: Its getting dirtier and dirtier. Simply calling this again after a column has been set to visible (see note 1) doesn't always suffice (also not with a Platform.runLater call). I assume that's because the column header hasn't been rendered at that point. You either

  • need to wait until the Set<Node> is fully filled, i.e. the size of it must be amountOfVisibleColumns + 1. If its equal to the amount of visible columns, it won't work for the newly shown column.
  • or call layout() on the TableView before lookupAll
  • or if you have a class that extends TableView, override layoutChildren and execute the lookup if the amount of visible columns has changed

Note 3: You need to keep track of the old onMousePressed and execute it if the button isn't SECONDARY, otherwise the reordering of columns won't work.

Please let me know if you can think of any cleaner way.

enter image description here

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);
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=149379&siteId=1