【问题标题】:Getting LocalDate to display in a Tableview in Javafx让 LocalDate 在 Javafx 的 Tableview 中显示
【发布时间】:2018-10-17 20:14:32
【问题描述】:

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

这是主控制器:

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 类,负责从文件中读取数据并生成可观察的数组列表:

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 部分:

<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 中设置日期SimpleStringProperty,然后在我的代码的所有其他部分将其转换为LocalDate,但这似乎没有必要。我感谢任何人能给我的任何见解。

【问题讨论】:

    标签: java javafx tableview localdate


    【解决方案1】:

    TL;DR 版本:您将 cellValueFactorycellFactory 混淆了。例如,请参阅 this tutorial 以获得对差异的很好解释,以下是针对此特定示例的总结。

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

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

    或者,如果您更喜欢使用(有些旧的)PropertyValueFactory 类,您可以这样做

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

    后一个版本具有(许多缺点,但只有一个)优点,即它也可以在 FXML 中完成。但请注意,您需要的是cellValueFactory,而不是cellFactory。所以你的 FXML 应该是

    <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&lt;TableColumn&lt;Holiday, LocalDate&gt;, TableCell&lt;Holiday, LocalDate&gt;&gt; 表示,即将TableColumn&lt;Holiday, LocalDate&gt; 映射到TableCell&lt;Holiday, LocalDate&gt; 的函数。 ClassCastException 发生是因为您设置的单元工厂将通过 TableColumn,但预计会收到 CellDataFeatures,因此当它尝试这样处理时,转换失败。

    除了单元格值工厂之外,您可能还需要一个单元格工厂,以便您可以控制如何显示日期(例如控制用于它的格式)。如果你给日期列一个fx:id,比如&lt;TableColumn fx:id="dateColumn"&gt;,然后将它注入到控制器中

    @FXML
    private TableColumn<Holiday, LocalDate> dateColumn ;
    

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

    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));
                }
            }
        });
    }
    

    【讨论】:

    • 非常感谢您修复了它。你的解释清楚了很多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    • 2018-11-13
    • 2016-09-02
    • 2014-07-28
    相关资源
    最近更新 更多