让LocalDate显示在Javafx的Tableview中 [英] Getting LocalDate to display in a Tableview in Javafx

查看:561
本文介绍了让LocalDate显示在Javafx的Tableview中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在处理我的应用程序的一部分,该应用程序允许用户输入他们学校起飞的假期并将其保存到文件中。从文件中读取假日的名称和日期(存储为LocalDate对象)并存储在假日对象中并放入可观察的arraylist中。

I have been working on part of my application that allows a user to input holidays that their school takes off and saves it to a file. The name of the holiday and the date (stored as a LocalDate object) is read from the file and stored in a holiday object and put into an observable arraylist.

这是主控制器:

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Optional;


public class Controller {
    @FXML
    private BorderPane mainGridPane;
    private ArrayList<Job> jobs = new ArrayList<>();
    private static XSSFRow row;
    private boolean fileClosed = false;
    @FXML
    private DatePicker employeeStartDate;
    @FXML
    private Label evaluation40;
    @FXML
    private Label evaluation80;
    @FXML
    private Label evaluation120;
    @FXML
    private DatePicker summerStart;
    @FXML
    private DatePicker summerEnd;
    @FXML
    private DatePicker fallStart;
    @FXML
    private DatePicker fallEnd;
    @FXML
    private TableView<Holiday> tableView;

    private HolidayData data;

    public void initialize() throws IOException {
        data = new HolidayData();
        data.loadHolidays();
        tableView.setItems(data.getHolidays());

    }

这是假期类:

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import java.time.LocalDate;

public class Holiday {
    private SimpleStringProperty name = new SimpleStringProperty();
    private ObjectProperty<LocalDate> date;


    public Holiday(String name, LocalDate date) {
        this.name.set(name);
        this.date = new SimpleObjectProperty<>(date);
    }

    public String getName() {
        return name.get();
    }

    public SimpleStringProperty nameProperty() {
        return name;
    }

    public LocalDate getDate() {
        return date.get();
    }

    public ObjectProperty<LocalDate> dateProperty() {
        return date;
    }

这是HolidayData类,负责从文件读取数据生成和观察到的arraylist:

This is the HolidayData class that is responsible for reading the data to and from files and producing and observable arraylist:

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;

public class HolidayData {
     private static HolidayData instance = new HolidayData();
     private static String fileName = "schoolHolidays.txt";
     private DateTimeFormatter formatter;

     private ObservableList<Holiday> holidays;

     public HolidayData(){
         formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
     }

    public static HolidayData getInstance() {
        return instance;
    }

    public static String getFileName() {
        return fileName;
    }

    public ObservableList<Holiday> getHolidays(){
         return holidays;
    }

    public void addHoliday(Holiday holiday){
         holidays.add(holiday);
    }


    public void loadHolidays() throws IOException {
        holidays = FXCollections.observableArrayList();
        Path path = Paths.get(fileName);
        BufferedReader br = Files.newBufferedReader(path);

        String input;
        try{
            while((input = br.readLine()) != null){
                String[] holidayPieces = input.split("\t");

                String name = holidayPieces[0];
                String dateString =  holidayPieces[1];

                LocalDate date = LocalDate.parse(dateString, formatter);
                Holiday holiday = new Holiday(name, date);
                holidays.add(holiday);
            }
        }catch(IOException e) {
            e.printStackTrace();
        } finally{
            if(br != null){
                br.close();
            }
        }
    }

    public void storeHolidays()throws IOException{
        Path path = Paths.get(fileName);
        BufferedWriter bw = Files.newBufferedWriter(path);
        try {
            Iterator<Holiday> iter = holidays.iterator();
            while(iter.hasNext()){
                Holiday holiday = iter.next();
                bw.write(String.format("%s\t%s", holiday.getName(), holiday.getDate().format(formatter)));
                bw.newLine();
            }
        }finally {
            if (bw != null){
                bw.close();
            }

        }
    }

    public void deleteHoliday(Holiday holiday){
        holidays.remove(holiday);
    }
}

这是FXML文件的tableView部分:

This is the tableView portion of the FXML file:

<TableView fx:id="tableView">
    <columnResizePolicy>
        <TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
    </columnResizePolicy>
    <columns>
        <TableColumn text="Holiday Name">
            <cellFactory>
                <PropertyValueFactory property="name"/>
            </cellFactory>
        </TableColumn>
        <TableColumn text="Date">
            <cellFactory>
                <PropertyValueFactory property="date" />
            </cellFactory>
        </TableColumn>
    </columns>
</TableView>

我遇到的问题是 java.lang.ClassCastException 说表列不能转换为某个对象,我认为是 LocalDate 对象。我使用SimpleObjectProperty将它数据绑定到FXML文件,但我似乎无法让它工作。我能想到的另一件事就是在 Holiday a SimpleStringProperty 中创建日期并将其转换为 LocalDate 在我的代码中的所有其他部分,但这似乎是不必要的。我很感激任何人都能给我的见解。

The problem I am running into is java.lang.ClassCastException saying the table column cannot be cast to a certain object, which I think is the LocalDate object. I am using the SimpleObjectProperty to databind it to the FXML file, but I can't seem to get it to work. The only other thing I can think to do is just make the date in Holiday a SimpleStringProperty and convert that to a LocalDate in all the other parts in my code, but that seems unnecessary. I appreciate any insight anyone can give me.

推荐答案

TL; DR版本:你混淆了 cellValueFactory 使用 cellFactory 。例如,请参阅本教程,以获得更好的解释差异,这是为下面这个特定的例子总结的。

TL;DR version: you are confusing the cellValueFactory with the cellFactory. See, for example, this tutorial for a nice explanation of the difference, which is summarized for this particular example below.

表列的 cellValueFactory 是一个告诉的对象要在单元格中显示的值,或者更确切地说,如何从表示每行的对象中获取这些值。这由 Callback< CellDataFeatures< Holiday,LocalDate>,ObservableProperty< LocalDate>> 表示,即映射 CellDataFeatures< Holiday,LocalDate>的函数; ObservableValue< LocalDate> 。所以在Java代码中你会这样做

A table column's cellValueFactory is an object that tells the column which values to display in the cells, or more precisely how to get those values from the objects representing each row. This is represented by a Callback<CellDataFeatures<Holiday, LocalDate>, ObservableProperty<LocalDate>>, i.e. a function mapping a CellDataFeatures<Holiday, LocalDate> to an ObservableValue<LocalDate>. So in Java code you would do

dateColumn.setCellValueFactory(holidayRowData -> holidayRowData.getValue().dateProperty());

或者,如果您更喜欢使用(有点遗留) PropertyValueFactory class,你可以做到

or, if you prefer to use the (somewhat legacy) PropertyValueFactory class, you can do

dateColumn.setCellValueFactory(new PropertyValueFactory<>("date"));

后一版本具有(很多缺点,但一方面)可以在FXML中完成的优势同样。但请注意,您需要 cellValueFactory ,而不是 cellFactory 。所以你的FXML应该是

The latter version has the (many disadvantages, but the one) advantage that it can be done in FXML as well. Note, though, that you want the cellValueFactory, not the cellFactory. So your FXML should be

<TableView fx:id="tableView">
    <columnResizePolicy>
        <TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
    </columnResizePolicy>
    <columns>
        <TableColumn text="Holiday Name">
            <cellValueFactory>
                <PropertyValueFactory property="name"/>
            </cellValueFactory>
        </TableColumn>
        <TableColumn text="Date">
            <cellValueFactory>
                <PropertyValueFactory property="date" />
            </cellValueFactory>
        </TableColumn>
    </columns>
</TableView>

相比之下, cellFactory 是一个告诉列如何显示数据的对象。它由 Callback< TableColumn< Holiday,LocalDate>,TableCell< Holiday,LocalDate>> 表示,即映射 TableColumn< Holiday的函数,LocalDate> TableCell< Holiday,LocalDate> 。发生 ClassCastException ,因为您设置的单元格工厂将传递 TableColumn ,但是期望收到 CellDataFeatures ,所以当它试图像这样处理时,演员表会失败。

The cellFactory, by contrast, is an object that tells the column how to display the data. It is represented by a Callback<TableColumn<Holiday, LocalDate>, TableCell<Holiday, LocalDate>>, i.e a function mapping a TableColumn<Holiday, LocalDate> to a TableCell<Holiday, LocalDate>. The ClassCastException occurs because the cell factory you set is going to be passed the TableColumn, but is expecting to receive a CellDataFeatures, and so when it tries to treat it as such, the cast fails.

你可能想要一个单元格这里的工厂,除了单元格值工厂,以便您可以控制如何显示日期(例如,控制用于它的格式)。如果您给日期列指定 fx:id ,请说< TableColumn fx:id =dateColumn> ,并将其注入控制器

You may well want a cell factory here, in addition to the cell value factory, so that you can control how the date is displayed (e.g. control the format used for it). If you give the date column an fx:id, say <TableColumn fx:id="dateColumn">, and inject it into the controller with

@FXML
private TableColumn<Holiday, LocalDate> dateColumn ;

然后在控制器的初始化方法中,你可以这样做:

then in the controller's initialize method, you can do:

public void initialize() throws IOException {
    data = new HolidayData();
    data.loadHolidays();
    tableView.setItems(data.getHolidays());

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    dateColumn.setCellFactory(column -> new TableCell<Holiday, LocalDate>() {
        @Override
        protected void updateItem(LocalDate date, boolean empty) {
            super.updateItem(date, empty);
            if (empty) {
                setText("");
            } else {
                setText(formatter.format(date));
            }
        }
    });
}

这篇关于让LocalDate显示在Javafx的Tableview中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆