美文网首页JavaFX
如何使用JavaFX构建一个具有分页和全局排序的TabbleVi

如何使用JavaFX构建一个具有分页和全局排序的TabbleVi

作者: Huangjs1994 | 来源:发表于2018-08-06 19:16 被阅读210次

    JavaFX提供了TableView用来显示数据,但是TableView没有分页功能,并且在加上分页功能后,TableViewjinjin只能在一页里面排序。
    完整示例见:https://github.com/lhuangjs/blog/tree/master/src/main/java/javafx/tableview

    学英语 ing,注释使用英文,如有不当,请指教

    第一步:创建带有分页功能的TableView

    1. 首先我们新建一个Page类,用来管理数据

    • Page.java: 省略getter和setter方法
    import javafx.beans.property.SimpleIntegerProperty;
    
    import java.util.List;
    
    public class Page<T> {
        private SimpleIntegerProperty totalRecord; // total record number in source data
        private SimpleIntegerProperty pageSize; // the number of data in per page
        private SimpleIntegerProperty totalPage; // total page number
        private List<T> rowDataList; // total data
    
        /** setter **
        /** getter **/
     
       /**
         * @param rowDataList
         * @param pageSize    the number of data in per page
         */
        public Page(List<T> rowDataList, int pageSize) {
            this.totalRecord = new SimpleIntegerProperty();
            this.totalPage = new SimpleIntegerProperty();
            this.rowDataList = rowDataList;
            this.pageSize = new SimpleIntegerProperty(pageSize);
            initialize();
    
    
        }
    
        private void initialize() {
            totalRecord.set(rowDataList.size());
    
            // calculate the number of total pages
            totalPage.set(
                    totalRecord.get() % pageSize.get() == 0 ?
                            totalRecord.get() / pageSize.get() :
                            totalRecord.get() / pageSize.get() + 1);
    
            // add listener: the number of total pages need to be change if the page size changed
            pageSize.addListener((observable, oldVal, newVal) ->
                    totalPage.set(
                            totalRecord.get() % pageSize.get() == 0 ?
                                    totalRecord.get() / pageSize.get() :
                                    totalRecord.get() / pageSize.get() + 1)
            );
        }
    
        /**
         * current page number(0-based system)
         *
         * @param currentPage current page number
         * @return
         */
        public List<T> getCurrentPageDataList(int currentPage) {
            int fromIndex = pageSize.get() * currentPage;
            int tmp = pageSize.get() * currentPage + pageSize.get() - 1;
            int endIndex = tmp >= totalRecord.get() ? totalRecord.get() - 1 : tmp;
    
            // subList(fromIndex, toIndex) -> [fromIndex, toIndex)
            return rowDataList.subList(fromIndex, endIndex + 1);
        }
    }
    
    • 这个Page类的作用是传入一个需要分页的数据(rowDataList)和每页显示的行数(pageSize),然后在initialize()方法中自动计算:数据的总记录数(totalRecord),总页数(totalPage)。
    • 这里使用了SimpleIntegerProperty类,这个类使得我们方便地为变量添加监听器。
            pageSize.addListener((observable, oldVal, newVal) ->
                    totalPage.set(
                            totalRecord.get() % pageSize.get() == 0 ?
                                    totalRecord.get() / pageSize.get() :
                                    totalRecord.get() / pageSize.get() + 1)
            );
    

    在程序中,为变量pageSize添加了一个监听器,如果pageSize的值改变,那么总页数(totalPage)也需要随之改变。

    • Page.getCurrentPageDataList(int currentPage)会根据传入的页码,返回当前页的数据
    • 使用泛型,便于组件的重用

    2. 添加分页功能到TableView

    • TableWithPaginationAndSorting.java: 省略getter方法
    import javafx.collections.FXCollections;
    import javafx.scene.control.Pagination;
    import javafx.scene.control.TableView;
    
    public class TableWithPaginationAndSorting<T> {
        private Page<T> page;
        private TableView<T> tableView;
        private Pagination tableViewWithPaginationPane;
        
        /** getter **/
    
        public TableWithPaginationAndSorting(Page<T> page, TableView<T> tableView) {
            this.page = page;
            this.tableView = tableView;
            tableViewWithPaginationPane = new Pagination();
            tableViewWithPaginationPane.pageCountProperty().bindBidirectional(page.totalPageProperty());
            updatePagination();
        }
    
        private void updatePagination() {
            tableViewWithPaginationPane.setPageFactory(pageIndex -> {
                tableView.setItems(FXCollections.observableList(page.getCurrentPageDataList(pageIndex)));
                return tableView;
            });
        }
    }
    
    • 这个类中最重要的是方法updatePagination,这个方法体中设置了Pagination的页面工厂,这里使用Lambda表达式传入一个回调方法,回调方法会在一个页面被选中时触发。它会加载并返回被选中页面的内容。如果当前被选中的页面索引不存在,则必须返回null值。在这个回调方法中:我们接收传过来的当前页码(pageIndex,从0开始),然后利用Page对象的getCurrentPageDataList(pageIndex)方法获取当页的数据,转换格式并添加到TableView中,最后返回TableView。

    关于page factory,可以将它想象成一个加工厂,它负责根据提供的页码生产对应的页面,所以,你可以根据不同的页码显示不同的内容。并且这里我们不用每次都新建一个表格,只需要每次将数据添加到建好了的表格框架

    image.png
    • tableViewWithPaginationPane.pageCountProperty().bindBidirectional(page.totalPageProperty());这一段代码是将PaginationpageCountPropertyPage对象的page.totalPageProperty属性进行双向绑定,这样他们的值就会同步:其中一个改变,另一个也会改变,并且值保持一样。
      如果不使用Lambda,也可以使用匿名函数:
        private void updatePagination() {
            tableViewWithPaginationPane.setPageFactory(new Callback<Integer, Node>() {
    
                @Override
                public Node call(Integer pageIndex) {
                    tableView.setItems(FXCollections.observableList(page.getCurrentPageDataList(pageIndex)));
                    return tableView;
                }
            });
        }
    

    3. 建立一个测试类

    我们先建立一个测试类来测试我们已经开发的功能。

    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.scene.Scene;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    
    import java.util.Arrays;
    import java.util.List;
    
    public class TableWithPaginationAndSortingTest extends Application {
    
        @Override
        public void start(Stage primaryStage) throws Exception {
    
            // create table
            TableView<People> peopleTable = createTable();
    
            // get data
            List<People> peopleList = getTableData();
            peopleTable.setItems(FXCollections.observableList(peopleList));
    
            // create Page object
            Page<People> page = new Page<>(peopleList, 2);
    
            // add pagination into table
            TableWithPaginationAndSorting<People> table = new TableWithPaginationAndSorting<>(page, peopleTable);
    
            Scene scene = new Scene(new BorderPane(table.getTableViewWithPaginationPane()), 300, 300);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private TableView<People> createTable() {
            TableView<People> table = new TableView<>();
            TableColumn<People, String> nameCol = new TableColumn<>("name");
            nameCol.setCellValueFactory(new PropertyValueFactory("name"));
            TableColumn<People, Integer> ageCol = new TableColumn<>("age");
            ageCol.setCellValueFactory(new PropertyValueFactory("age"));
            table.getColumns().addAll(nameCol, ageCol);
            table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
            return table;
        }
    
        private List<People> getTableData() {
            return Arrays.asList(new People[]{
                            new People("Huang1", 18),
                            new People("Huang2", 11),
                            new People("Huang3", 13),
                            new People("Huang4", 28),
                            new People("Huang5", 38)
                    }
            );
        }
    
        public class People {
            private String name;
            private int age;
    
            public People(String name, int age) {
                this.name = name;
                this.age = age;
            }
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public int getAge() {
                return age;
            }
    
            public void setAge(int age) {
                this.age = age;
            }
        }
    }
    
    • 我们创建了一个内部类People用作表格展示,然后使用方法createTable()getTableData()来创建TableView和产生表格数据。
    • start()方法中将所有组件组装起来。
      image
    • 我们带有分页功能的TableView创建成功了,我们可以点击表头进行排序,但是这是局部排序,只能对当前页的内容进行排序。


      image.png

    相关文章

      网友评论

        本文标题:如何使用JavaFX构建一个具有分页和全局排序的TabbleVi

        本文链接:https://www.haomeiwen.com/subject/gdkgvftx.html