为什么此JavaFX TableView滚动条未正确更新?

时间:2013-12-22 05:33:17

标签: javafx javafx-8

编辑:我filed a bug report就此问题而言。事实证明我不小心对b118运行了这个例子,而不是b120。这个错误在b118和b120之间的某个时间被修复了,所有东西都按预期使用b120。

我正在使用JavaFX 8(OpenJDK的120版本),而我在使用TableView滚动时遇到了问题。这是一个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;
        }
    }
}

我正在使用FilteredList,但我也遇到了一个未经过滤的ObservableList问题。运行上面的示例,不要触摸表,并使用文本字段筛选表项。尝试将表格降至约50项。我认为过滤器wil(WIL)效果很好。

一旦列表中只有约50个项目,请尝试向下滚动。滚动条(手柄)的大小不正确。 Here is a screenshot表明了我的意思。底部的标签显示已过滤列表中的项目数。注意表格如何滚动到最后一项,但滚动条看起来仍然在列表中有~2000项?

另请注意,如果您在开始之前滚动表格中的第一项似乎正常工作。有谁知道这里出了什么问题?

1 个答案:

答案 0 :(得分:4)

这是在JDK 8 EA预览的b118和b120之间修复的错误。它使用b120按预期工作。