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?

Community
  • 1
  • 1
user3804927
  • 749
  • 1
  • 7
  • 15
  • 2
    Can you use a `ListView` instead of a `TableView`, since you only have one column? – James_D Nov 25 '14 at 05:19
  • 1
    I can verify that the **lookup id** is still available in JavaFX 8. Is the `list` reference to a `TableView`? – ItachiUchiha Nov 25 '14 at 05:27
  • @James_D 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. – user3804927 Nov 25 '14 at 06:41
  • @ItachiUchiha 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. – user3804927 Nov 25 '14 at 06:43
  • 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 TableView – tomsontom Nov 25 '14 at 07:24
  • 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. – user3804927 Nov 25 '14 at 08:32
  • @tomsontom Let's say I have ListView, 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. – user3804927 Nov 25 '14 at 09:18
  • 1
    Set a cell factory on the ListView. – James_D Nov 25 '14 at 09:37

5 Answers5

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.

Christian Lutz
  • 538
  • 3
  • 12
9

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
        }
);
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Thank you for the clarification. I didn't know about Cell Factory, so this does look simpler once I understand how it works. Cheers! – user3804927 Nov 25 '14 at 21:09
  • 1
    downvoted, does not answer original question, please answer the question, THEN suggest a better means of solving their problem, then will upvote, thanks. – Troyseph Jun 22 '15 at 20:40
  • 2
    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. – James_D Jun 22 '15 at 23:35
  • 2
    @James_D 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... – Troyseph Jun 23 '15 at 18:33
  • 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? – James_D Jun 23 '15 at 18:50
  • 1
    @James_D 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... – Troyseph Jun 24 '15 at 07:28
  • 3
    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](http://meta.stackexchange.com/questions/66377/what-is-the-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. – James_D Jun 24 '15 at 12:32
  • 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). – James_D Jun 24 '15 at 12:33
  • 1
    Thank you for clarifying, upvoted for the extra effort – Troyseph Jun 24 '15 at 15:25
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.

Don Wills
  • 393
  • 1
  • 3
  • 6
3

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.

Freewind
  • 193,756
  • 157
  • 432
  • 708
zIronManBox
  • 4,967
  • 6
  • 19
  • 35
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);
    });
}
lolung
  • 460
  • 3
  • 16