TableColumn<Event,Date> releaseTime = new TableColumn<>("Release Time");
releaseTime.setCellValueFactory(
new PropertyValueFactory<Event,Date>("releaseTime")
);
如何更改 releaseTime 的格式?目前它在 Date 对象上调用一个简单的 toString。
如果您想保留 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 ,我花了一段时间才弄清楚这一点;所以希望这会为其他人节省一些时间!
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));
}
}
};
};
}
优点是:
我建议使用 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")));
我最近需要这样做 -
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!
您可以通过细胞工厂实现这一目标。请参阅
https://stackoverflow.com/a/10149050/682495
https://stackoverflow.com/a/10700642/682495
虽然第二个链接是 about ListCell
,但同样的逻辑也完全适用于TableCell
s。
PS 如果您需要一些示例代码,请在此处附上。
一个通用的解决方案可能很简单:
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));
这就是我所做的,我工作得很好。
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")));
}
}
};
});
您可以轻松地通过管道传输不同类型的属性,并在两者之间放置一个格式化程序或转换器。
//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;
});
类StringConverter
是另一种机制。
TextFieldTableCell
有一个构造函数如下:public TextFieldTableCell(StringConverter<T> converter)
.
... 和StringConverter
s 由子类组成,例如LocalDateStringConverter
. 然后,默认实现将是:
new TextFieldTableCell( new LocalDateStringConverter() );
...这还不错,但是无参数LocalDateStringConverter
使用格式为“dd/mm/yyyy”的日期进行解析(fromString()
方法)和toString()
. 但是还有其他构造函数可以传递 aFormatStyle
或DateTimeFormatter
.
然而,从我的实验来看,StringConverter
s 存在一些问题,因为它很难捕捉到无效日期的DateTimeParseException
抛出。fromString()
这可以通过创建自己的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
表示形式如何。