Edit: I've filed a bug report for this issue. It turns out I was accidentally running this example against b118, not b120. This bug was fixed sometime between b118 and b120 and everything works as expected for me using b120.
I'm using JavaFX 8 (build 120 of OpenJDK) and I'm having trouble with TableView scrolling incorrectly. Here is a SSCCE:
import javafx.application.Application;
import javafx.beans.binding.IntegerBinding;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class TableViewScroll extends Application {
private final ObservableList<Person> personList = FXCollections.observableArrayList();
private final FilteredList<Person> filteredPersonList = new FilteredList<>(personList);
private final StringProperty filterText = new SimpleStringProperty();
private final IntegerProperty count = new SimpleIntegerProperty();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
Scene scene = createScene();
initPersonList();
bindCount();
addFilterListener();
primaryStage.setTitle("Table View Scroll");
primaryStage.setScene(scene);
primaryStage.show();
}
private Scene createScene() {
VBox vBox = new VBox();
vBox.setPadding(new Insets(5));
vBox.setSpacing(5);
TableView<Person> resultsTable = new TableView<>();
TableColumn<Person, String> indexColumn = new TableColumn<>("#");
indexColumn.setCellValueFactory(param -> {
// assumes unique list items
int index = resultsTable.getItems().indexOf(param.getValue());
return new ReadOnlyStringWrapper(Integer.toString(index + 1));
});
TableColumn<Person, String> nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
resultsTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
resultsTable.getColumns().setAll(indexColumn, nameColumn);
resultsTable.setItems(filteredPersonList);
TextField filterTextField = new TextField();
filterTextField.textProperty().bindBidirectional(filterText);
Label countLabel = new Label();
countLabel.textProperty().bind(count.asString());
vBox.getChildren().setAll(filterTextField, resultsTable, countLabel);
return new Scene(vBox);
}
private void initPersonList() {
String firstNames = "Adam, Adrian, Alan, Alexander, Andrew, Anthony," +
" Austin, Benjamin, Blake, Boris, Brandon, Brian, Cameron," +
" Carl, Charles, Christian, Christopher, Colin, Connor, Dan," +
" David, Dominic, Dylan, Edward, Eric, Evan, Frank, Gavin," +
" Gordon, Harry, Ian, Isaac, Jack, Jacob, Jake, James, Jason," +
" Joe, John, Jonathan, Joseph, Joshua, Julian, Justin, Keith," +
" Kevin, Leonard, Liam, Lucas, Luke, Matt, Max, Michael," +
" Nathan, Neil, Nicholas, Oliver, Owen, Paul, Peter, Phil," +
" Piers, Richard, Robert, Ryan, Sam, Sean, Sebastian, Simon," +
" Stephen, Steven, Stewart, Thomas, Tim, Trevor, Victor," +
" Warren, William";
String[] firstNameArray = firstNames.split("\\s*,\\s*");
String lastNames = "Abraham, Allan, Alsop, Anderson, Arnold, Avery," +
" Bailey, Baker, Ball, Bell, Berry, Black, Blake, Bond," +
" Bower, Brown, Buckland, Burgess, Butler, Cameron, Campbell," +
" Carr, Chapman, Churchill, Clark, Clarkson, Coleman," +
" Cornish, Davidson, Davies, Dickens, Dowd, Duncan, Dyer," +
" Edmunds, Ellison, Ferguson, Fisher, Forsyth, Fraser," +
" Gibson, Gill, Glover, Graham, Grant, Gray, Greene," +
" Hamilton, Hardacre, Harris, Hart, Hemmings, Henderson," +
" Hill, Hodges, Howard, Hudson, Hughes, Hunter, Ince," +
" Jackson, James, Johnston, Jones, Kelly, Kerr, King, Knox," +
" Lambert, Langdon, Lawrence, Lee, Lewis, Lyman, MacDonald," +
" Mackay, Mackenzie, MacLeod, Manning, Marshall, Martin," +
" Mathis, May, McDonald, McLean, McGrath, Metcalfe, Miller," +
" Mills, Mitchell, Morgan, Morrison, Murray, Nash, Newman," +
" Nolan, North, Ogden, Oliver, Paige, Parr, Parsons," +
" Paterson, Payne, Peake, Peters, Piper, Poole, Powell," +
" Pullman, Quinn, Rampling, Randall, Rees, Reid, Roberts," +
" Robertson, Ross, Russell, Rutherford, Sanderson, Scott," +
" Sharp, Short, Simpson, Skinner, Slater, Smith, Springer," +
" Stewart, Sutherland, Taylor, Terry, Thomson, Tucker," +
" Turner, Underwood, Vance, Vaughan, Walker, Wallace, Walsh," +
" Watson, Welch, White, Wilkins, Wilson, Wright, Young";
String[] lastNameArray = lastNames.split("\\s*,\\s*");
int firstNameLength = firstNameArray.length;
int lastNameLength = lastNameArray.length;
Random firstRandomIndex = new Random();
Random lastRandomIndex = new Random();
// Use a set to ensure all names are unique
Set<String> names = new HashSet<>();
for (int i = 0; i < 2000; i++) {
String first = firstNameArray[firstRandomIndex.nextInt(firstNameLength)];
String last = lastNameArray[lastRandomIndex.nextInt(lastNameLength)];
names.add(first + " " + last);
}
for (String name : names) {
personList.add(new Person(name));
}
}
private void bindCount() {
count.bind(new IntegerBinding() {
{
bind(filteredPersonList);
}
@Override
protected int computeValue() {
return filteredPersonList.size();
}
});
}
private void addFilterListener() {
filterText.addListener((o, old, filter) ->
filteredPersonList.setPredicate(person -> {
String[] terms = filter.split("\\s");
for (String term : terms) {
if (person.getName().toLowerCase().contains(term.toLowerCase())) {
return true;
}
}
return false;
}));
}
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}
I'm using a FilteredList
, but I also have problems with a single, unfiltered, ObservableList
. Run the above example, don't touch the table, and use the text field to filter the table items. Try to get the table down to ~50 items. I think the filter wil
(WIL) works quite well.
Once there are only ~50 items in the list, attempt to scroll down. The size of the scroll bar (handle) is incorrect. Here is a screenshot that shows what I mean. The label at the bottom shows a count of items in the filtered list. Notice how the table is scrolled to the last item, but the scrollbar still looks like there are ~2000 items in the list?
Also note, if you scroll the first item in the table out of view before starting it seems to work correctly. Does anyone know what's going wrong here?
This is a bug that was fixed somewhere between b118 and b120 of the JDK 8 EA Previews. It works as expected using b120.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With