How to hide TableView column header in JavaFX 8?
Asked Answered
C

5

6

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?

Chafer answered 25/11, 2014 at 4:34 Comment(8)
Can you use a ListView instead of a TableView, since you only have one column?Helban
I can verify that the lookup id is still available in JavaFX 8. Is the list reference to a TableView?Agler
@Helban I could, but I have a list of Albums that I need to work with such that if an album is selected, the rest of the album object needs to be passed from the Table to the right pane. TableView works directly with the object, whereas a ListView would require me to mess about with the album name and index separately to the object. If I am wrong, please enlighten me, thanks.Chafer
@Agler Thanks for your confirmation. It is in fact a TableView, so I can't figure out why it is giving me a return of null. As you've seen by the screenshot, that is the Table which I'm working with.Chafer
James_D is right use ListView, i can't follow you with your problem with it because the domain object would be the same as the one you pass to TableViewChallah
Found what the problem is... The TableView has to be rendered first before the lookup method can be successfully called. Note the instruction advise to use after stage.show(). However, this is not entirely true (as in my case) if you're only working with one stage while passing containers as a way to switch between viewsports. Thanks ItachiUchiha for confirming that this still works in JavaFX8.Chafer
@Challah Let's say I have ListView<Album>, how do I get the ListView to only display the name of the album? On selection I want to pass an album to the right pane which is why the object must be of the type Album. TableView allows me to only display "one" field from the Album type using a TableColumn.Chafer
Set a cell factory on the ListView.Helban
H
8

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
        }
);
Helban answered 25/11, 2014 at 12:45 Comment(9)
Thank you for the clarification. I didn't know about Cell Factory, so this does look simpler once I understand how it works. Cheers!Chafer
downvoted, does not answer original question, please answer the question, THEN suggest a better means of solving their problem, then will upvote, thanks.Malinowski
It actually solves the problem posed in the question, which clearly stated that he needs a single column without a header. If your question is different, ask it as a new question.Helban
@Helban I never said it didn't solve OPs problem, I said it didn't answer the Question How to hide TableView column header in JavaFX 8? If I asked my own, it would also be How to hide TableView column header in JavaFX 8? and then it would be a duplicate...Malinowski
That's the title of the question, not the question itself. But what is wrong with the solution outlined in the comments? Why would I duplicate the solution already provided in the comments below the question?Helban
@Helban What the hell is the point of this site if the Title question isn't answered in the answers? The issue with your solution is that it doesn't use a TableView . I have multiple columns, I use functionality not present in a ListView, I've tried the same things as the OP and would ask exactly the same question again, except that isn't the point of this site...Malinowski
The problem is that it's not a well-asked question. First, there's not enough code to reproduce the problem (the actual posted code is fine, it's just that the context in which it's executed is wrong, as per the discussion in the comments below the question). Secondly, the OP is asking how to fix the wrong solution to the original problem (known as an XY problem. These are hard to answer, because it actually doesn't help the OP if you just fix the wrong solution. I disagree with you on this, but I edited anyway.Helban
If that still doesn't fix your problem, then your question is genuinely different, and you should ask it yourself (even if you give it the same title, it is still a different question).Helban
Thank you for clarifying, upvoted for the extra effortMalinowski
K
21

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.

Kunstlied answered 22/2, 2017 at 12:34 Comment(1)
Return null, if used during tableView init. Need to call, only after TableView is rendered.Freehearted
H
8

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
        }
);
Helban answered 25/11, 2014 at 12:45 Comment(9)
Thank you for the clarification. I didn't know about Cell Factory, so this does look simpler once I understand how it works. Cheers!Chafer
downvoted, does not answer original question, please answer the question, THEN suggest a better means of solving their problem, then will upvote, thanks.Malinowski
It actually solves the problem posed in the question, which clearly stated that he needs a single column without a header. If your question is different, ask it as a new question.Helban
@Helban I never said it didn't solve OPs problem, I said it didn't answer the Question How to hide TableView column header in JavaFX 8? If I asked my own, it would also be How to hide TableView column header in JavaFX 8? and then it would be a duplicate...Malinowski
That's the title of the question, not the question itself. But what is wrong with the solution outlined in the comments? Why would I duplicate the solution already provided in the comments below the question?Helban
@Helban What the hell is the point of this site if the Title question isn't answered in the answers? The issue with your solution is that it doesn't use a TableView . I have multiple columns, I use functionality not present in a ListView, I've tried the same things as the OP and would ask exactly the same question again, except that isn't the point of this site...Malinowski
The problem is that it's not a well-asked question. First, there's not enough code to reproduce the problem (the actual posted code is fine, it's just that the context in which it's executed is wrong, as per the discussion in the comments below the question). Secondly, the OP is asking how to fix the wrong solution to the original problem (known as an XY problem. These are hard to answer, because it actually doesn't help the OP if you just fix the wrong solution. I disagree with you on this, but I edited anyway.Helban
If that still doesn't fix your problem, then your question is genuinely different, and you should ask it yourself (even if you give it the same title, it is still a different question).Helban
Thank you for clarifying, upvoted for the extra effortMalinowski
F
4

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.

Freehearted answered 24/4, 2017 at 10:39 Comment(1)
getTableHeaderRow is not visible anymore.Asclepiadaceous
B
4

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.

Boehmenism answered 14/6, 2017 at 2:39 Comment(0)
A
0

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);
    });
}
Asclepiadaceous answered 17/2, 2022 at 16:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.