JavaFX 表格单元格格式

Posted

技术标签:

【中文标题】JavaFX 表格单元格格式【英文标题】:JavaFX Table Cell Formatting 【发布时间】:2012-07-09 20:57:24 【问题描述】:
    TableColumn<Event,Date> releaseTime  = new TableColumn<>("Release Time");
    releaseTime.setCellValueFactory(
                new PropertyValueFactory<Event,Date>("releaseTime")
            );

如何更改 releaseTime 的格式?目前它在 Date 对象上调用一个简单的 toString。

【问题讨论】:

【参考方案1】:

如果您想保留 TableColumn 的排序功能,上述解决方案均无效:如果您将 Date 转换为 String 并在 TableView 中以这种方式显示;该表将按原样对其进行排序(因此不正确)。

我找到的解决方案是继承 Date 类以覆盖 toString() 方法。不过这里有一个警告:TableView 使用 java.sql.Date 而不是 java.util.Date;所以你需要继承前者。

import java.text.SimpleDateFormat;

public class CustomDate extends java.sql.Date 

    public CustomDate(long date) 
        super(date);
    

    @Override
    public String toString() 
        return new SimpleDateFormat("dd/MM/yyyy").format(this);
    

表格将调用该方法以打印日期。

当然,您也需要将 TableColumn 声明中的 Date 类更改为新的子类:

@FXML
TableColumn<MyObject, CustomDate> myDateColumn;

将对象属性附加到表格列时也是如此:

myDateColumn.setCellValueFactory(new PropertyValueFactory< MyObject, CustomDate>("myDateAttr"));

最后,为了清楚起见,这是您在对象类中声明 getter 的方式:

public CustomDate getMyDateAttr() 
    return new CustomDate(myDateAttr.getTime()); //myDateAttr is a java.util.Date           

由于它在幕后使用 java.sql.Date,我花了一段时间才弄清楚这一点;所以希望这可以为其他人节省一些时间!

【讨论】:

【参考方案2】:

Java FX8 更新:

(我不确定这是否是该答案的好地方,但我在 JavaFX8 中遇到了问题,并且有些事情发生了变化,例如 java.time 包)

与之前的答案有些不同: 我将日期类型保留在列上,因此我需要同时使用 cellValueFactory 和 cellFactory。 我制作了一个通用的可重用方法来为所有日期列生成 cellFactory。 我使用 java.time 包的 java 8 日期!但是该方法可以很容易地为 java.util.date 重新实现。

 @FXML
 private TableColumn<MyBeanUi, ZonedDateTime> dateColumn;

@FXML
public void initialize () 
  // The normal binding to column 
  dateColumn.setCellValueFactory(cellData -> cellData.getValue().getCreationDate());

  //.. All the table initialisation and then
  DateTimeFormatter format = DateTimeFormatter .ofLocalizedDate(FormatStyle.SHORT);
  dateColumn.setCellFactory (getDateCell(format));



public static <ROW,T extends Temporal> Callback<TableColumn<ROW, T>, TableCell<ROW, T>> getDateCell (DateTimeFormatter format) 
  return column -> 
    return new TableCell<ROW, T> () 
      @Override
      protected void updateItem (T item, boolean empty) 
        super.updateItem (item, empty);
        if (item == null || empty) 
          setText (null);
        
        else 
          setText (format.format (item));
        
      
    ;
  ;

优点是:

该列使用“java8 Date”键入以避免@Jordan 引发的排序问题 “getDateCell”方法是通用方法,可用作所有 Java8 时间类型(Local Zoned 等)的实用函数

【讨论】:

是的,我的实验似乎表明,即使您使用非 ISO 日期格式(其排序就像它的 String 当然等效(2020-04-23 等)!)这使得列可以按时间顺序排序。【参考方案3】:

我建议使用 Java 泛型来创建可重用的列格式化程序,它接受任何 java.text.Format。这减少了样板代码的数量...

private class ColumnFormatter<S, T> implements Callback<TableColumn<S, T>, TableCell<S, T>> 
    private Format format;

    public ColumnFormatter(Format format) 
        super();
        this.format = format;
    
    @Override
    public TableCell<S, T> call(TableColumn<S, T> arg0) 
        return new TableCell<S, T>() 
            @Override
            protected void updateItem(T item, boolean empty) 
                super.updateItem(item, empty);
                if (item == null || empty) 
                    setGraphic(null);
                 else 
                    setGraphic(new Label(format.format(item)));
                
            
        ;
    

使用示例

birthday.setCellFactory(new ColumnFormatter<Person, Date>(new SimpleDateFormat("dd MMM YYYY")));
amplitude.setCellFactory(new ColumnFormatter<Levels, Double>(new DecimalFormat("0.0dB")));

【讨论】:

但是使用的是哪个属性?您的示例中没有属性名称。 @MaxiWu 除了上面的 setCellFactory(),你仍然需要调用 setCellValueFactory() 来绑定一个实际的属性【参考方案4】:

我最近需要这样做 -

dateAddedColumn.setCellValueFactory(
   new Callback<TableColumn.CellDataFeatures<Film, String>, ObservableValue<String>>() 
      @Override
      public ObservableValue<String> call(TableColumn.CellDataFeatures<Film, String> film) 
         SimpleStringProperty property = new SimpleStringProperty();
         DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
         property.setValue(dateFormat.format(film.getValue().getCreatedDate()));
         return property;
      
   );

但是 - 在 Java 8 中使用 Lamba 表达式会更容易很多

dateAddedColumn.setCellValueFactory(
   film -> 
      SimpleStringProperty property = new SimpleStringProperty();
      DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
      property.setValue(dateFormat.format(film.getValue().getCreatedDate()));
      return property;
   );

快点使用 Java 8 版本的 oracle!

【讨论】:

这适用于最初填充表格...如果模型中的日期属性更改晚于 SimpleStringProperty 不发出通知,并且表格未更新。【参考方案5】:

您可以通过细胞工厂实现这一目标。见https://***.com/a/10149050/682495https://***.com/a/10700642/682495 虽然第二个链接是关于ListCell,但同样的逻辑也完全适用于TableCells。

附:如果您需要一些示例代码,请在此处附上。

【讨论】:

【参考方案6】:

一个通用的解决方案可以这么简单:

import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;

public interface AbstractConvertCellFactory<E, T> extends Callback<TableColumn<E, T>, TableCell<E, T>> 

    @Override
    default TableCell<E, T> call(TableColumn<E, T> param) 
        return new TableCell<E, T>() 
            @Override
            protected void updateItem(T item, boolean empty) 
                super.updateItem(item, empty);
                if (item == null || empty) 
                    setText(null);
                 else 
                    setText(convert(item));
                
            
        ;
    

    String convert(T value);        

及其示例用法:

TableColumn<Person, Timestamp> dateCol = new TableColumn<>("employment date");
dateCol.setCellValueFactory(new PropertyValueFactory<>("emploumentDateTime"));    
dateCol.setCellFactory((AbstractConvertCellFactory<Person, Timestamp>) value -> new SimpleDateFormat("dd-MM-yyyy").format(value));

【讨论】:

【参考方案7】:

这就是我所做的,而且我工作得很好。

tbColDataMovt.setCellFactory((TableColumn<Auditoria, Timestamp> column) -> 
    return new TableCell<Auditoria, Timestamp>() 
        @Override
        protected void updateItem(Timestamp item, boolean empty) 
            super.updateItem(item, empty);
            if (item == null || empty) 
                setText(null);
             else 
                setText(item.toLocalDateTime().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
            
        
    ;
);

【讨论】:

【参考方案8】:

您可以轻松地通过管道传输不同类型的属性,并在两者之间放置格式化程序或转换器。

    //from my model
    ObjectProperty<Date> valutaProperty;

    //from my view
    TableColumn<Posting, String> valutaColumn;

    valutaColumn.setCellValueFactory(
            cellData -> 
                  SimpleStringProperty property = new SimpleStringProperty();
                  property.bindBidirectional(cellData.getValue().valutaProperty,  new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN));
                  return property;
               );

【讨论】:

【参考方案9】:

StringConverter 类是另一种机制。

TextFieldTableCell 的构造函数如下:public TextFieldTableCell(StringConverter&lt;T&gt; converter)

... 和StringConverters 由诸如LocalDateStringConverter 之类的子类组成。然后,默认实现将是:

new TextFieldTableCell( new LocalDateStringConverter() );

...这还不错,但无参数LocalDateStringConverter 使用格式为“dd/mm/yyyy”的日期进行解析(fromString() 方法)和toString()。但是还有其他构造函数可以传递FormatStyleDateTimeFormatter

然而,从我的实验来看,StringConverters 有一点问题,因为很难捕获 fromString() 抛出的带有无效日期的 DateTimeParseException

这可以通过创建自己的StringConverter 类来解决,例如:

class ValidatingLocalDateStringConverter extends LocalDateStringConverter 
    boolean valid;

    @Override
    LocalDate fromString(String value) 
        valid = true;
        if (value.isBlank()) return null;
        try 
            // NB wants ISO
            return LocalDate.parse( value );
         catch ( DateTimeParseException e) 
            valid = false;
        
        return null;
    

    @Override
    String toString( LocalDate date )
        // NB returns ISO or the String "null" with null date value (!)
        String s = date.toString();
        return s.equals( 'null' )? '' : s;
    

使用此StringConverter 解决方案将意味着日期按时间顺序排序,而不管String 表示形式如何。

【讨论】:

以上是关于JavaFX 表格单元格格式的主要内容,如果未能解决你的问题,请参考以下文章

JavaFX:如何使表格单元格取决于另一个表格单元格的值

电子表格 - 基于其他单元格的条件格式单元格

我的excel表格打开的单元格格式默认为日期,请问如何让excel表格打开的单元格格式默认为常规

excel单元格格式改不了怎么办

Excel表格自定义数字格式如何设置

基于两个单元格的 Google 表格条件格式