使用 FXCollections.observableArrayList() 从数据库填充 treetableview

Populate treetableview from database using FXCollections.observableArrayList()

我有一个支出报告查询,它生成每天的字段总计(指定为“root”列为 1)和当天的下拉详细信息(指定为“root”列为 2)。我可以直接填充 table 视图没问题,可以直接填充树 table 视图而无需使用 FXCollections.observableArrayList()。问题是我需要使用 FXCollections.observableArrayList(),因为我将使用 rowchecker()cellchecker(),它们使用 cellFactory 回调来检查单元格值并更改特定单元格的背景或者更改填充 table 视图时有效的整行背景。这是我的目标: 从数据库结果集中填充一个树table视图;隐藏父级并用 “root” = 1 填充树 table 视图,每个日期用 “root” = 2;根据单元格值更改 cell/row 的背景颜色。

package TreeTableView;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.ResourceBundle;
import com.jfoenix.controls.RecursiveTreeItem;

import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.util.Callback;
    public class FXMLDocument implements Initializable{

    Connection conn = null;
    ResultSet rs = null;
    PreparedStatement pst = null;
    Integer idjobs = 286; //temp
    Integer idjobs_by = 6; //temp
    Integer loginID = 4;

    @FXML
    private TreeTableView<ER_Report> tableview;
    ObservableList<ER_Report> ER_report = FXCollections.observableArrayList();

    @FXML
    private TreeTableColumn<ER_Report, Number> col1;

    @FXML
    private TreeTableColumn<ER_Report, String> col2;

    @FXML
    private TreeTableColumn<ER_Report, String> col3;

    @FXML
    private TreeTableColumn<ER_Report, String> col4;

    TreeItem<ER_Report> root;

    public void dataset() {         
        String sql = "SELECT * FROM expensereport_total_withlist where job = '" + idjobs + "' and jobby = '" + idjobs_by + "' and employee  = '" + loginID + "' "
                + "order by newSort, root";
        try {
            pst = conn.prepareStatement(sql);
            rs = pst.executeQuery();
            while(rs.next()) {
                DecimalFormat df2 = new DecimalFormat("###0.00");
                DecimalFormat df3 = new DecimalFormat("###0.000");

            Integer c_rootI = 0;
            Date c_Date;
            Integer c_WorkedDayI = 0;
            String c_MealsS = "";
            String c_AirfareS = "";

    c_rootI = rs.getInt("root");
    String c_rootS = c_rootI.toString();
    c_Date = rs.getDate("newSort");
    String c_DateS = c_Date.toString();
    c_WorkedDayI = rs.getInt("workedDay");
    String c_WorkedDayS = c_WorkedDayI.toString();
    Double c_MealsD = rs.getDouble("Meals");
           if(c_MealsD > 0) {
               c_MealsS = "$ " + df2.format(c_MealsD) ;
           }    
    Double c_airD = rs.getDouble("Meals");
        if(c_airD > 0) {
            c_AirfareS = "$ " + df2.format(c_airD) ;
               }

        ER_report.add(new ER_Report(c_rootI, c_DateS,c_MealsS,c_AirfareS));     
            }
            final TreeItem<ER_Report> root = new RecursiveTreeItem<ER_Report>(ER_report, RecursiveTreeObject::getChildren);         


            col1.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<ER_Report, Number>, ObservableValue<Number>>() {               
                @Override
                public ObservableValue<Number> call(TreeTableColumn.CellDataFeatures<ER_Report, Number> param) {
                    return param.getValue().getValue().rootProperty;
                }
            });             
            col2.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<ER_Report, String>, ObservableValue<String>>() {               
                @Override
                public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<ER_Report, String> param) {
                    return param.getValue().getValue().newDateProperty;
                }
            });
            col3.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<ER_Report, String>, ObservableValue<String>>() {               
                @Override
                public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<ER_Report, String> param) {
                    return param.getValue().getValue().mealsProperty;
                }
            });
            col4.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<ER_Report, String>, ObservableValue<String>>() {               
                @Override
                public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<ER_Report, String> param) {
                    return param.getValue().getValue().airProperty;
                }
            });


            root.getChildren().setAll(root);
            tableview.setRoot(root);            
    }catch(Exception e) {
         e.printStackTrace();
    }
        root = new TreeItem<>(new ER_Report(0, "Name", "None", "None"));
    }

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        conn = connector.ConnectDb();

        idjobs = 286; //temp
        idjobs_by = 6; //temp
        dataset();
    }

    class ER_Report extends RecursiveTreeObject<ER_Report>{ 
        SimpleIntegerProperty rootProperty;
        SimpleStringProperty newDateProperty;
        SimpleStringProperty mealsProperty;
        SimpleStringProperty airProperty;

        public ER_Report(Integer root, String newDate, String meals, String air) {
            this.rootProperty = new SimpleIntegerProperty(root);
            this.newDateProperty = new SimpleStringProperty(newDate);
            this.mealsProperty = new SimpleStringProperty(meals);
            this.airProperty = new SimpleStringProperty(air);
        }

        /**
         * @return the rootProperty
         */
        public SimpleIntegerProperty getRootProperty() {
            return rootProperty;
        }

        /**
         * @param rootProperty the rootProperty to set
         */
        public void setRootProperty(SimpleIntegerProperty rootProperty) {
            this.rootProperty = rootProperty;
        }

        /**
         * @return the newDateProperty
         */
        public SimpleStringProperty getNewDateProperty() {
            return newDateProperty;
        }

        /**
         * @param newDateProperty the newDateProperty to set
         */
        public void setNewDateProperty(SimpleStringProperty newDateProperty) {
            this.newDateProperty = newDateProperty;
        }

        /**
         * @return the mealsProperty
         */
        public SimpleStringProperty getMealsProperty() {
            return mealsProperty;
        }

        /**
         * @param mealsProperty the mealsProperty to set
         */
        public void setMealsProperty(SimpleStringProperty mealsProperty) {
            this.mealsProperty = mealsProperty;
        }

        /**
         * @return the airProperty
         */
        public SimpleStringProperty getAirProperty() {
            return airProperty;
        }

        /**
         * @param airProperty the airProperty to set
         */
        public void setAirProperty(SimpleStringProperty airProperty) {
            this.airProperty = airProperty;
        }


    }
}

接下来是查询结果

newSort root    Meals   Airfare
6/22/2018   1   94.16   756.46
6/22/2018   2   NULL    756.46
6/22/2018   2   38.53   NULL
6/22/2018   2   55.63   NULL
6/27/2018   1   6.92    NULL
6/27/2018   2   3.63    NULL
6/27/2018   2   3.29    NULL
6/29/2018   1   NULL    698.9
6/29/2018   2   NULL    698.9

这是我正在使用的行检查器。我目前没有将要查看的列包含在结果集中,但您可以看到我将使用的代码。

 public void rowchecker() {
        Callback<TableColumn<ExpenseReportTable, Integer>, TableCell<ExpenseReportTable, Integer>> cellFactory
        = new Callback<TableColumn<ExpenseReportTable, Integer>, TableCell<ExpenseReportTable, Integer>>() {
public TableCell call(TableColumn p) {
    TableCell cell = new TableCell<ExpenseReportTable, Integer>() {
        @Override
        public void updateItem(Integer item, boolean empty) {
            super.updateItem(item, empty);
            if (!empty) {
                  TableRow ttr = getTableRow();
                  if (item == null || empty){
                      setText(null);
                      ttr.setStyle("");
                      setStyle("");
                  } else {
                      ttr.setStyle(item.doubleValue() > 0 
                              ? "-fx-background-color:lightgreen"
                              : "-fx-background-color:#FFE793");
                      setText(item.toString());
                      setStyle(item.doubleValue() > 0 
                              ? "-fx-background-color:green"
                              : "-fx-background-color:lightgreen");
                  }
            } else {
                setText(null);
            }
        }

        private String getString() {
            return getItem() == null ? "" : getItem().toString();
        }
    };

    return cell;
}
};
col_NonWorkedDate.setCellFactory(cellFactory);

    }

我能够按照我的意愿弄清楚它在哪里工作。下面是代码。

package TreeTableView;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.ResourceBundle;

import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.util.Callback;

public class FXMLDocument implements Initializable{
    Connection conn = null;
    ResultSet rs = null;
    PreparedStatement pst = null;
    Integer idjobs;
    Integer idjobs_by;
    Integer loginID;

    @FXML
    private TreeTableView<ERItems> tableview;
    TreeItem root = new TreeItem<>("rootxxx");

    @FXML
    private TreeTableColumn<ERItems, Integer> col1;

    @FXML
    private TreeTableColumn<ERItems, String> col2;

    @FXML
    private TreeTableColumn<ERItems, String> col3;

    @FXML
    private TreeTableColumn<ERItems, String> col4;


    @Override
    public void initialize(URL url, ResourceBundle rb) {
        conn = connector.ConnectDb();           
        idjobs = 286; 
        idjobs_by = 6; 
        loginID = 4;

        dataset2();     

        tableview.setEditable(true);

            Platform.runLater(() -> {

            col2.setCellValueFactory(cellData -> {
            if (cellData.getValue().getValue()instanceof ERItems) {
                return new ReadOnlyObjectWrapper(cellData.getValue().getValue().getCol_date());
            }
            return new ReadOnlyObjectWrapper(cellData.getValue().getValue());
        });

            col3.setCellValueFactory(cellData -> {
            if (cellData.getValue().getValue()instanceof ERItems) {
                return new ReadOnlyObjectWrapper(cellData.getValue().getValue().getCol_meals());
            }
            return new ReadOnlyObjectWrapper(cellData.getValue().getValue());
        });    

            col1.setMinWidth(0);
            col1.setMaxWidth(0);
            col1.setCellValueFactory(cellData -> {
            if (cellData.getValue().getValue()instanceof ERItems) {
                return new ReadOnlyObjectWrapper(cellData.getValue().getValue().getCol_workedDay());
            }
            return new ReadOnlyObjectWrapper(cellData.getValue().getValue());
        }); 

            col4.setCellValueFactory(cellData -> {
            if (cellData.getValue().getValue()instanceof ERItems) {
                return new ReadOnlyObjectWrapper(cellData.getValue().getValue().getCol_air());
            }
            return new ReadOnlyObjectWrapper(cellData.getValue().getValue());
        }); 

            tableview.setTreeColumn(col2);
            tableview.setRoot(root);                
            tableview.setShowRoot(false);
            rowchecker();
            root.setExpanded(true);
        });   
}

    public void dataset2() {
        String sql = "SELECT * FROM expensereport_total_withlist where job = '" + idjobs + "' and jobby = '" + idjobs_by + "' and employee  = '" + loginID + "' "
                + "order by newSort, root";
        try {
            pst = conn.prepareStatement(sql);
            rs = pst.executeQuery();                

            String currentDate = null;
            String currentRoot = null;
            TreeItem<String> tiDate = null;
            TreeItem<String> tiRoot = null;  
            TreeItem<ERItems> nodeRoot = null;
            TreeItem<ERItems> nodeChild = null;
            ReliantER tiReliantER = null;
            TreeItem<ReliantER> nodeItem = null;
            Integer inputRowCounter = 0;

            while(rs.next()) {              
                DecimalFormat df2 = new DecimalFormat("###0.00");
                DecimalFormat df3 = new DecimalFormat("###0.000");                  
                Integer c_rootI = 0;
                Date c_Date;
                Integer c_WorkedDayI = 0;
                String c_MealsS = "";
                String c_AirfareS = "";

                c_rootI = rs.getInt("root");
                String c_rootS = c_rootI.toString();
                c_Date = rs.getDate("newSort");
                String c_DateS = c_Date.toString();
                c_WorkedDayI = rs.getInt("workedDay");
                String c_WorkedDayS = c_WorkedDayI.toString();
                Double c_MealsD = rs.getDouble("Meals");
                   if(c_MealsD > 0) {
                       c_MealsS = "$ " + df2.format(c_MealsD) ;
                   }    

                Double c_airD = rs.getDouble("Airfare");
                    if(c_airD > 0) {
                        c_AirfareS = "$ " + df2.format(c_airD) ;
                   }    

                    if (c_rootI == 1 ){
                        nodeRoot = new TreeItem<> (new ERItems(rs.getInt("workedDay"), c_DateS, c_MealsS, c_AirfareS)); 
                        root.getChildren().add(nodeRoot);
                    }else{
                        if(rs.getInt("receiptActive") == 1) {
                            nodeChild = new TreeItem<> (new ERItems(rs.getInt("workedDay"), c_DateS, c_MealsS, c_AirfareS));    
                            nodeRoot.getChildren().add(nodeChild);
                        }
                    }
                        inputRowCounter = inputRowCounter + 1;        
                }   
            } catch (SQLException e) {
                e.printStackTrace();
                Alert a1 = new Alert(Alert.AlertType.ERROR);
                a1.showAndWait();
            }                       
    }        


public void rowchecker() {
    Callback<TreeTableColumn<ERItems, Integer>, TreeTableCell<ERItems, Integer>> cellFactory
    = new Callback<TreeTableColumn<ERItems, Integer>, TreeTableCell<ERItems, Integer>>() {
        public TreeTableCell call(TreeTableColumn p) {
            TreeTableCell cell = new TreeTableCell<ERItems, Integer>() {
                @Override
                public void updateItem(Integer item, boolean empty) {
                    super.updateItem(item, empty);
                    if (!empty) {
                          TreeTableRow ttr = getTreeTableRow();
                          if (item == null || empty){
                              setText(null);
                              ttr.setStyle("");
                              setStyle("");
                          } else {
                             ttr.setStyle(item.doubleValue() > 0 
                                      ? ""
                                      : "-fx-background-color:#FFE793");
                              setText(item.toString());
                           //   setStyle(item.doubleValue() > 0 
                           //           ? "-fx-background-color:green"
                           //           : "-fx-background-color:lightgreen");
                          }
                    } else {
                        setText(null);
                    }
                }       
                private String getString() {
                    return getItem() == null ? "" : getItem().toString();
                }
            };      
            return cell;
        }
    };
    col1.setCellFactory(cellFactory);   
    }

public static class ERItems {

    private final SimpleIntegerProperty col_workedDay;
    private final SimpleStringProperty col_meals;
    private final SimpleStringProperty col_air;
    private final SimpleStringProperty col_date;



    private ERItems(Integer col_workedDay, String col_date, String col_meals, String col_air) {
        this.col_workedDay = new SimpleIntegerProperty(col_workedDay);
        this.col_date = new SimpleStringProperty(col_date);
        this.col_meals = new SimpleStringProperty(col_meals);
        this.col_air = new SimpleStringProperty(col_air);
    }


    public String getCol_meals() {
        return col_meals.get();
    }

    public String getCol_air() {
        return col_air.get();
    }

    public String getCol_date() {
        return col_date.get();
    }


    public Integer getCol_workedDay() {
        return col_workedDay.get();
    }

}       

}

现在它为我提供了 Treetable,其中包含当天总计的父行和当天个人收据的子行。然后 rowchecker 查看 col1 以查看是否是员工记录工作时间的一天,并突出显示他们当天是否有费用的行。

Treetableview result