How to hide TableView column header in JavaFX 8?

19.6k views Asked by At

I need to have an observable list of a type that will be displayed in a TableView with one single column, that when selected will display the rest of its information on the right. The TableView is wrapped in a TitledPane, which is wrapped in an Accordion. See image below:

enter image description here

As you can see in this scenario I don't want to show the Column Header.

I tried following the instruction here, which leads to here:

Pane header = (Pane) list.lookup("TableHeaderRow");
header.setMaxHeight(0);
header.setMinHeight(0);
header.setPrefHeight(0);
header.setVisible(false);

However, it appears to not be working for JavaFX 8. The lookup("TableHeaderRow") method returns null which makes me think that the "TableHeaderRow" selector no longer exist.

Is there an updated workaround for removing/hiding the table header in JavaFX 8?

5

There are 5 answers

9
James_D On BEST ANSWER

As observed in the comments, lookups do not work until after CSS has been applied to a node, which is typically on the first frame rendering that displays the node. Your suggested solution works fine as long as you execute the code you have posted after the table has been displayed.

For a better approach in this case, a single-column "table" without a header is just a ListView. The ListView has a cell rendering mechanism that is similar to that used for TableColumns (but is simpler as you don't have to worry about multiple columns). I would use a ListView in your scenario, instead of hacking the css to make the header disappear:

ListView<Album> albumList = new ListView<>();
albumList.setCellFactory((ListView<Album> lv) -> 
    new ListCell<Album>() {
        @Override
        public void updateItem(Album album, boolean empty) {
            super.updateItem(album, empty);
            if (empty) {
                setText(null);
            } else {
                // use whatever data you need from the album
                // object to get the correct displayed value:
                setText(album.getTitle());
            }
        }
    }
);

albumList.getSelectionModel().selectedItemProperty()
    .addListener((ObservableValue<? extends Album> obs, Album oldAlbum, Album selectedAlbum) -> {
        if (selectedAlbum != null) {
            // do something with selectedAlbum
        }
);
1
Christian Lutz On

I faced the problem of hiding column headers recently and could solve it using css.

I created a styleclass:

.noheader .column-header-background {
    -fx-max-height: 0;
    -fx-pref-height: 0;
    -fx-min-height: 0;
}

and added it to the TableView:

tableView.getStyleClass().add("noheader");

Just in case someone needs an alternative approach. It also gives the flexibility of toggling column headers.

0
lolung On

Combining the last two answers for a more generic solution without the need to override methods because getTableHeaderRow is no longer visible to be accessed. Tested with Java 11:

private void hideHeaders() {
    table.skinProperty().addListener((a, b, newSkin) ->
    {
      Pane header = (Pane) table.lookup("TableHeaderRow");
      header.setMinHeight(0);
      header.setPrefHeight(0);
      header.setMaxHeight(0);
      header.setVisible(false);
    });
}
1
zIronManBox On

Also, I would recommend using this nowadays.

tableView.skinProperty().addListener((a, b, newSkin) -> {
    TableHeaderRow headerRow = ((TableViewSkinBase) 
newSkin).getTableHeaderRow();
    ...
});

This can be executed during initialization, the other method as mention above, will return null, if run during initialization.

0
Don Wills On

There's no need for CSS or style or skin manipulation. Simply make a subclass of TableView and override resize, like this

class XTableView extends TableView {
    @Override
    public void resize(double width, double height) {
        super.resize(width, height);
        Pane header = (Pane) lookup("TableHeaderRow");
        header.setMinHeight(0);
        header.setPrefHeight(0);
        header.setMaxHeight(0);
        header.setVisible(false);
    }
}

This works fine as of June 2017 in Java 8.