JavaFx TableView(表格控件)与Pagination(分页控件)结合

一个完善的数据查询界面,是不能没有分页的

效果:

框架:SpringBoot+JavaFx+Hibernate

fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>


<BorderPane maxHeight="-Infinity" maxWidth="-Infinity"
            minHeight="-Infinity" minWidth="-Infinity"
            prefHeight="600.0" prefWidth="800.0"
            xmlns="http://javafx.com/javafx/8"
            xmlns:fx="http://javafx.com/fxml/1"
            fx:controller="com.maxinhai.world.controller.DynamicTableViewController">
   <top>
      <HBox prefHeight="42.0" prefWidth="800.0" BorderPane.alignment="CENTER">
         <children>
            <Button mnemonicParsing="false" text="首页" onAction="#toIndex">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </HBox.margin>
            </Button>
            <Button mnemonicParsing="false" text="新增">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </HBox.margin>
            </Button>
            <Button mnemonicParsing="false" text="查询">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </HBox.margin>
            </Button>
            <Button mnemonicParsing="false" text="修改">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </HBox.margin>
            </Button>
            <Button mnemonicParsing="false" text="删除">
               <HBox.margin>
                  <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
               </HBox.margin>
            </Button>
         </children>
      </HBox>
   </top>
   <center>
      <VBox prefHeight="200.0" prefWidth="100.0" BorderPane.alignment="CENTER">
         <children>
            <HBox prefHeight="43.0" prefWidth="800.0">
               <children>
                  <Label id="codeLabel" fx:id="codeLabel" alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefWidth="75.0" text="编码:" textAlignment="CENTER">
                     <HBox.margin>
                        <Insets bottom="10.0" left="10.0" top="10.0" />
                     </HBox.margin>
                  </Label>
                  <TextField id="codeText" prefWidth="180.0" fx:id="coedTextField">
                     <HBox.margin>
                        <Insets bottom="5.0" right="5.0" top="5.0" />
                     </HBox.margin>
                  </TextField>
                  <Label id="nameLabel" fx:id="nameLabel" alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefWidth="75.0" text="名称:" textAlignment="CENTER">
                     <HBox.margin>
                        <Insets bottom="10.0" left="20.0" top="10.0" />
                     </HBox.margin>
                  </Label>
                  <TextField id="codeText" prefWidth="180.0" fx:id="nameTextField">
                     <HBox.margin>
                        <Insets bottom="5.0" right="5.0" top="5.0" />
                     </HBox.margin>
                  </TextField>
               </children>
            </HBox>
            <HBox prefHeight="42.0" prefWidth="800.0">
               <children>
                  <Label text="开始时间:">
                     <HBox.margin>
                        <Insets bottom="10.0" left="10.0" top="10.0" />
                     </HBox.margin>
                  </Label>
                  <DatePicker prefWidth="180.0" fx:id="beginDatePicker">
                     <HBox.margin>
                        <Insets bottom="5.0" right="5.0" top="5.0" />
                     </HBox.margin>
                  </DatePicker>
                  <Label text="结束时间:">
                     <HBox.margin>
                        <Insets bottom="10.0" left="20.0" top="10.0" />
                     </HBox.margin>
                  </Label>
                  <DatePicker prefWidth="180.0" fx:id="endDatePicker">
                     <HBox.margin>
                        <Insets bottom="5.0" right="5.0" top="5.0" />
                     </HBox.margin>
                  </DatePicker>
               </children>
            </HBox>
            <HBox prefHeight="473.0" prefWidth="800.0" fx:id="parent">
               <children>
                  <!--实现分页插件与表格控件结合的关键在于两者要在同一个父容器下-->
                  <TableView prefHeight="100.0" prefWidth="802.0" fx:id="tableView" />
                  <Pagination fx:id="pagination" pageCount="10" prefHeight="35.0" prefWidth="800.0" BorderPane.alignment="CENTER" />
               </children>
            </HBox>
         </children>
      </VBox>
   </center>
   <bottom>
      <!--错误位置-->
      <!--<Pagination fx:id="pagination" pageCount="10" prefHeight="35.0" prefWidth="800.0" BorderPane.alignment="CENTER" />-->
   </bottom>
</BorderPane>

controller:

import com.maxinhai.world.WorldApplication;
import com.maxinhai.world.entity.ClientClockInRecord;
import com.maxinhai.world.repository.ClientClockInRepository;
import com.maxinhai.world.service.impl.DynamicTableViewServiceImpl;
import com.maxinhai.world.utils.ModuleUtils;
import de.felixroske.jfxsupport.FXMLController;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.util.Callback;
import org.springframework.beans.factory.annotation.Autowired;

import java.net.URL;
import java.util.*;

/**
 * @program: world
 * @description: 动态表格控制器
 * @author: XinHai.Ma
 * @create: 2021-05-24 14:33
 */
@FXMLController
public class DynamicTableViewController extends BaseController implements Initializable {

    @FXML
    private TextField coedTextField;
    @FXML
    private TextField nameTextField;
    @FXML
    private Label codeLabel;
    @FXML
    private Label nameLabel;
    @FXML
    private DatePicker beginDatePicker;
    @FXML
    private DatePicker endDatePicker;
    @FXML
    private TableView<ClientClockInRecord> tableView;
    @FXML
    private HBox parent;
    @FXML
    private Pagination pagination;

    // 删除集合
    private List<String> deleteList = new ArrayList<>();
    // 编辑集合
    private List<String> updateList = new ArrayList<>();

    @Autowired
    private ClientClockInRepository clockInRepository;
    @Autowired
    private DynamicTableViewServiceImpl dynamicTableViewService;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // 初始化表格
        LinkedHashMap<String, String> columns = new LinkedHashMap<>();
        columns.put("gid", "主键");
        columns.put("clientId", "员工id");
        columns.put("clientName", "员工名称");
        columns.put("workStatus", "状态");
        columns.put("createBy", "创建者");
        columns.put("createTime", "创建时间");
        columns.put("editBy", "编辑者");
        columns.put("editTime", "编辑时间");
        List<TableColumn> columnList = ModuleUtils.createColumn(true, columns, deleteList, updateList);
        HashMap<String, Object> params = new HashMap<>();
        params.put("pageIndex", 1);
        params.put("pageSize", 28);
        Map<String, Object> result = dynamicTableViewService.select(params);
        List<ClientClockInRecord> dataList = (List<ClientClockInRecord>)result.get("data"); //clockInRepository.findAll();
        ModuleUtils.createDynamicTable(parent, tableView, columnList, dataList);

        // 初始化分页插件
        pagination.setCurrentPageIndex(0);
        pagination.setPageCount(Integer.valueOf(result.get("total").toString()));
        pagination.setPageFactory(new Callback<Integer, Node>() {
            @Override
            public Node call(Integer pageIndex) {
                return createPage(pageIndex);
            }
        });
        // 分页插件宽度(不设置分页插件宽度表格宽度也无法随窗口变化)
        WorldApplication.getScene().widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                pagination.setPrefWidth(newValue.doubleValue());
            }
        });
    }


    /**
     * 页面切换调用该方法
     * @param pageIndex
     * @return
     */
    private TableView<ClientClockInRecord> createPage(int pageIndex) {
        HashMap<String, Object> params = new HashMap<>();
        params.put("pageIndex", pageIndex);
        params.put("pageSize", 28);
        Map<String, Object> result = dynamicTableViewService.select(params);
        List<ClientClockInRecord> dataList = (List<ClientClockInRecord>)result.get("data");
        ObservableList<ClientClockInRecord> items = FXCollections.observableArrayList(dataList);
        tableView.setItems(items);
        return tableView;
    }


    @FXML
    public void select () {
        HashMap<String, Object> params = new HashMap<>();
        Map<String, Object> result = dynamicTableViewService.select(params);
        List<ClientClockInRecord> dataList = (List<ClientClockInRecord>)result.get("data");
    }

}

service:

import com.maxinhai.world.entity.ClientClockInRecord;
import com.maxinhai.world.repository.ClientClockInRepository;
import com.maxinhai.world.service.DynamicTableViewService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: world
 * @description: 动态表格业务层
 * @author: XinHai.Ma
 * @create: 2021-05-24 15:03
 */
@SuppressWarnings("all")
@Service
public class DynamicTableViewServiceImpl implements DynamicTableViewService {

    @Autowired
    private ClientClockInRepository clockInRepository;

    @Override
    public Map<String, Object> select(Map<String, Object> params) {
        String pageIndex = params.get("pageIndex").toString();
        String pageSize = params.get("pageSize").toString();
        PageRequest page = PageRequest.of(Integer.valueOf(pageIndex), Integer.valueOf(pageSize), Sort.Direction.DESC, "createTime");
        Page<ClientClockInRecord> recordPage = clockInRepository.findAll(new Specification<ClientClockInRecord>() {
            @Override
            public Predicate toPredicate(Root<ClientClockInRecord> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> condition = new ArrayList<Predicate>();
                condition.add(criteriaBuilder.equal(root.get("isDelete").as(Integer.class), 0));
                condition.add(criteriaBuilder.equal(root.get("isActive").as(Integer.class), 0));
                // 编号
                if (Objects.nonNull(params.get("code"))) {
                    condition.add(criteriaBuilder.equal(root.get("code").as(String.class), params.get("code").toString()));
                }
                // 名称
                if (Objects.nonNull(params.get("name"))) {
                    condition.add(criteriaBuilder.equal(root.get("name").as(String.class), params.get("name").toString()));
                }
                // 开始、结束时间
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                if (Objects.nonNull(params.get("beginTime")) && Objects.nonNull(params.get("endTime"))) {
                    // 开始时间和结束时间之内
                    String beginTime = params.get("beginTime").toString() + " 00:00:00";
                    String endTime = params.get("endTime").toString() + " 23:59:59";
                    condition.add(criteriaBuilder.between(root.<LocalDateTime>get("createTime"), LocalDateTime.parse(beginTime, formatter), LocalDateTime.parse(endTime, formatter)));
                } else if (Objects.nonNull(params.get("beginTime"))) {
                    // 大于开始时间
                    String beginTime = params.get("beginTime").toString() + " 00:00:00";
                    condition.add(criteriaBuilder.greaterThanOrEqualTo(root.<LocalDateTime>get("createTime"), LocalDateTime.parse(beginTime, formatter)));
                } else if (Objects.nonNull(params.get("endTime"))) {
                    // 小于结束时间
                    String beginTime = params.get("endTime").toString() + " 23:59:59";
                    condition.add(criteriaBuilder.lessThanOrEqualTo(root.<LocalDateTime>get("createTime"), LocalDateTime.parse(beginTime, formatter)));
                }
                Predicate[] p = new Predicate[condition.size()];
                return criteriaBuilder.and(condition.toArray(p));
            }
        }, page);
        Map<String, Object> result = new HashMap<>();
        result.put("data", recordPage.get().collect(Collectors.toList()));
        result.put("total", recordPage.getTotalPages());
        return result;
    }

}

dao:

import com.maxinhai.world.entity.ClientClockInRecord;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ClientClockInRepository extends JpaRepository<ClientClockInRecord, String>, JpaSpecificationExecutor<ClientClockInRecord> {

}

组件初始化代码:

    /**
     * 方法描述:根据columnList(表头集合)、dataList(数据集合)初始化tableView
     * 注意:设置TableView的宽高去适应界面的大小行不通,只能设置父元素的大小,让TableView自适应
     *
     * @param parentNode  父容器
     * @param tableView  tableView对象
     * @param columnList 表格字段集合
     * @param dataList   表格数据集合
     */
    public static void createDynamicTable(Pane parentNode, TableView tableView, List<TableColumn> columnList, List dataList) {
        AssertUtils.assertTrue(Objects.isNull(tableView), "Component is Null!");
        // 设置表格可编辑
        tableView.setEditable(true);
        // 设置多选
        tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        // 去掉空白多于列
        tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
        // 设置表头
        tableView.getColumns().addAll(columnList);
        // 更新表格数据
        ObservableList<ClientLoginRecord> data = FXCollections.observableArrayList(dataList);
        tableView.setItems(data);
        // 使tableView随窗口变化而变化
        WorldApplication.getScene().heightProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                parentNode.setPrefHeight(newValue.doubleValue());
            }
        });
        WorldApplication.getScene().widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                tableView.setPrefWidth(newValue.doubleValue());
            }
        });
    }


    /**
     * 根据isCheckBox、columns创建表格表头
     *
     * @param isCheckBox 是否创建多选列
     * @param columns    bean字段对应中文集合
     * @return
     */
    public static List<TableColumn> createColumn(boolean isCheckBox, LinkedHashMap<String, String> columns, List<String> delList, List<String> updList) {
        List<TableColumn> columnList = new ArrayList<>();
        // 多选框
        if (isCheckBox) {
            TableColumn<BaseEntity, CheckBox> checkCol = new TableColumn("单选框");
            checkCol.setMinWidth(30);
            checkCol.setMinWidth(30);
            checkCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<BaseEntity, CheckBox>, ObservableValue<CheckBox>>() {
                @Override
                public ObservableValue<CheckBox> call(TableColumn.CellDataFeatures<BaseEntity, CheckBox> param) {
                    CheckBox checkBox = new CheckBox();
                    // 设置checkBox居中,貌似没用
                    checkBox.setAlignment(Pos.CENTER);
                    checkBox.setOnAction(event -> {
                        boolean selected = checkBox.isSelected();
                        String gid = param.getValue().getGid();
                        if (selected) {
                            delList.add(gid);
                            updList.removeAll(updList);
                            updList.add(gid);
                            System.out.println("选中: " + gid);
                        } else {
                            delList.remove(gid);
                            updList.remove(gid);
                            System.out.println("取消选中: " + gid);
                        }
                    });
                    return new ReadOnlyObjectWrapper<CheckBox>(checkBox);
                }
            });
            columnList.add(checkCol);
        }

        // 序号列
        TableColumn seqCol = new TableColumn("序号");
        seqCol.setMinWidth(20);
        seqCol.setMinWidth(20);
        seqCol.setCellFactory(new IDCell<>());
        columnList.add(seqCol);

        Map<String, Double> defaultWidthMap = getDefaultWidthMap();

        // 创建其他表头
        columns.forEach((k, v) -> {
            TableColumn column = new TableColumn(v);
            if ("gid".equals(k)) {
                column.setVisible(false);
            }
            if (getDateColSet().contains(k)) {
                formatDateTimeCol(column);
            }
            if (Objects.isNull(defaultWidthMap.get(k))) {
                // 没有默认长度,设置100宽度
                column.setMinWidth(100);
            } else {
                column.setMinWidth(defaultWidthMap.get(k));
            }
            column.setCellValueFactory(new PropertyValueFactory<ClientLoginRecord, String>(k));
            columnList.add(column);
        });
        return columnList;
    }


    /**
     * 格式化时间字段(Java8)
     *
     * @param column
     */
    public static void formatDateTimeCol(TableColumn column) {
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        column.setCellFactory(data -> {
            TableCell<Object, LocalDateTime> cell = new TableCell<Object, LocalDateTime>() {
                @Override
                protected void updateItem(LocalDateTime item, boolean empty) {
                    super.updateItem(item, empty);
                    if (empty) {
                        setText(null);
                    } else {
                        if (item != null)
                            this.setText(format.format(item));
                    }
                }
            };
            return cell;
        });
    }


    /**
     * 格式化时间字段(Java7)
     *
     * @param column
     */
    public static void formatDateCol(TableColumn column) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        column.setCellFactory(data -> {
            TableCell<Object, Date> cell = new TableCell<Object, Date>() {
                @Override
                protected void updateItem(Date item, boolean empty) {
                    super.updateItem(item, empty);
                    if (empty) {
                        setText(null);
                    } else {
                        if (item != null)
                            this.setText(format.format(item));
                    }
                }
            };
            return cell;
        });
    }


    /**
     * 获取时间字段集合
     *
     * @return
     */
    public static Set<String> getDateColSet() {
        Set<String> colSet = new HashSet<>();
        colSet.add("createTime");
        colSet.add("editTime");
        return colSet;
    }


    /**
     * 刷新tableView
     *
     * @param tableView
     * @param dataList
     */
    public static void refresh(TableView tableView, List dataList) {
        ObservableList items = tableView.getItems();
        items.removeAll(items);
        items.addAll(dataList);
        tableView.refresh();
    }


    /**
     * 获取默认字段对应长度集合
     *
     * @return
     */
    public static Map<String, Double> getDefaultWidthMap() {
        Map<String, Double> map = new HashMap<>();
        map.put("gid", 350.00);
        map.put("account", 100.00);
        map.put("code", 100.00);
        map.put("description", 100.00);
        map.put("remark", 100.00);
        map.put("createBy", 100.00);
        map.put("createTime", 200.00);
        map.put("editBy", 100.00);
        map.put("editTime", 200.00);
        map.put("username", 200.00);
        map.put("password", 200.00);
        return map;
    }
原文地址:https://www.cnblogs.com/mxh-java/p/14805389.html