How do you get JavaFX ListView to be the height of

2019-04-18 13:10发布

If I create a ListView:

new ListView<>(FXCollections.observableArrayList("1", "2", "3"))

I would expect it to create a ListView with 3 rows. But it doesn't. It creates a ListView of 17 or so rows. Is there a way to tell ListView to always be the height such that whatever items are in it are always shown but no blank rows?

Having it auto width would also be useful, so it's always as wide as the widest row.

One purpose of this is that then it could be used in a ScrollPane. I know it has its own scrollbars, but they don't offer sufficient control.

标签: javafx-2
9条回答
Evening l夕情丶
2楼-- · 2019-04-18 13:47

Unfortunately there is not a nice, clean size Property of an ObservableList for us to bind to. Instead, it's doable by adding a ListChangeListener on the list, at least, that's how I've done it in the past. By default the size of each row should be 24px, and we need an extra pixel on the top and bottom for the ListView's edges. Otherwise we still have the ListView's scroll bar showing. First we'll create the ObservableList and the ListView, and set the initial height of the ListView:

/*
 * Each row in a ListView should be 24px tall.  Also, we have to add an extra
 * two px to account for the borders of the ListView.
 */
final int ROW_HEIGHT = 24;
final ObservableList items = FXCollections.observableArrayList("1", "2", "3");
final ListView list = new ListView(items);

// This sets the initial height of the ListView:
list.setPrefHeight(items().size() * ROW_HEIGHT + 2);

Now we have to add a ListChangeListener to the ObservableList. When the list changes, we simply change the set height of the ListView to match the new number of rows. If we know that we are never going to add or remove items from the ObservableList that is backing the ListView, then we can exclude the listener. Again, the height is the number of rows times the height per row plus two extra pixels for the borders:

/*
 * This listener will resize the ListView when items are added or removed
 * from the ObservableList that is backing the ListView:
 */
items.addListener(new ListChangeListener() {
    @Override
    public void onChanger(ListChangeListener.Change change) {
        list.setPrefHeight(items.size() * ROW_HEIGHT + 2);
    }
});

References: JavaFX ListView Documentation, JavaFX ObservableList Documentation

查看更多
在下西门庆
3楼-- · 2019-04-18 13:50

I found a relatively easy though still slightly hacky solution which works under the assumption that all non-empty cells have the same height: instead of parsing css or some such, add an InvalidationListener to your listView.getItems(); the first time your items list becomes non-empty, you recursively go through the ListViews children until you find an instance of ListCell where !cell.isEmpty(), and store the value of cell.getHeight(). Be sure to wrap that code in a Platform.runLater() so that it gets executed once the ListView layouting is done. Once you have that height, you multiply it with listView.getItems().size() and call listView.setMaxHeight with the resulting value (still inside the InvalidationListener).

查看更多
神经病院院长
4楼-- · 2019-04-18 13:52

I based my answer on the answers provided by @scribbleslims and @Alexandre Mazari

listView.setPrefHeight(listView.getItems().size() * LIST_CELL_HEIGHT);

You have to define LIST_CELL_HEIGHT on your own.

In my case, I used 29.501.

查看更多
登录 后发表回答