JavaFX Table Cell Formatting

匿名 (未验证) 提交于 2019-12-03 00:52:01

问题:

    TableColumn releaseTime  = new TableColumn("Release Time");     releaseTime.setCellValueFactory(                 new PropertyValueFactory("releaseTime")             ); 

How can I change the format of releaseTime? At the moment it calls a simple toString on the Date object.

回答1:

You can accomplish that through Cell Factories. See
https://stackoverflow.com/a/10149050/682495
https://stackoverflow.com/a/10700642/682495
Although the 2nd link is about ListCell, the same logic is totally applicable to TableCells too.

P.S. Still if you need some sample code, kindly will attach here.



回答2:

If you want to preserve the sorting capabilities of your TableColumn, none of the solutions above is valid: if you convert your Date to a String and show it that way in your TableView; the table will sort it as such (so incorrectly).

The solution I found was subclassing the Date class in order to override the toString() method. There is a caveat here though: the TableView uses java.sql.Date instead of java.util.Date; so you need to subclass the former.

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

The table will call that method in order to print the date.

Of course, you need to change too your Date class in the TableColumn declaration to the new subclass:

@FXML TableColumn myDateColumn; 

Same thing when you attach your object attribute to the column of your table:

myDateColumn.setCellValueFactory(new PropertyValueFactory("myDateAttr")); 

And finally, for the shake of clarity this is how you declare the getter in your object class:

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

It took me a while to figure out this due to the fact that it uses java.sql.Date behind the scenes; so hopefully this will save other people some time!



回答3:

I needed to do this recently -

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

However - it is a lot easier in Java 8 using Lamba Expressions:

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

Hurry up with that Java 8 release oracle!



回答4:

Update for Java FX8:

(I'm not sure it is the good place for that answer, but I get the problem in JavaFX8 and some things have changed, like java.time package)

Some differences with the previous answers: I keep the date type on the column, so I need to use both cellValueFactory and cellFactory. I Make a generic reusable method to generate the cellFactory for all date columns. I use java 8 date for java.time package! But the method could be easily reimplemented for java.util.date.

 @FXML  private TableColumn 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  Callback, TableCell> getDateCell (DateTimeFormatter format) {   return column -> {     return new TableCell () {       @Override       protected void updateItem (T item, boolean empty) {         super.updateItem (item, empty);         if (item == null || empty) {           setText (null);         }         else {           setText (format.format (item));         }       }     };   }; } 

The advantages are that:

  • The column is typed with a "java8 Date" to avoid the sort problem evoqued by @Jordan
  • The method "getDateCell" is generic and can be used as an util function for all Java8 Time types (Local Zoned etc.)


回答5:

I'd recommend using Java generics to create re-usable column formatter that takes any java.text.Format. This cuts down on the amount of boilerplate code...

private class ColumnFormatter implements Callback, TableCell> {     private Format format;      public ColumnFormatter(Format format) {         super();         this.format = format;     }     @Override     public TableCell call(TableColumn arg0) {         return new TableCell() {             @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)));                 }             }         };     } } 

Examples of usage

birthday.setCellFactory(new ColumnFormatter(new SimpleDateFormat("dd MMM YYYY"))); amplitude.setCellFactory(new ColumnFormatter(new DecimalFormat("0.0dB"))); 


回答6:

This is what i did and i worked perfectly.

tbColDataMovt.setCellFactory((TableColumn column) -> {     return new TableCell() {         @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")));             }         }     }; }); 


回答7:

An universal solution could be as simple as that:

import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.util.Callback;  public interface AbstractConvertCellFactory extends Callback, TableCell> {      @Override     default TableCell call(TableColumn param) {         return new TableCell() {             @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);         } 

And its sample usage:

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


回答8:

You can easily pipe Properties of different type and put a formatter or converter in between.

    //from my model     ObjectProperty valutaProperty;      //from my view     TableColumn valutaColumn;      valutaColumn.setCellValueFactory(             cellData -> {                   SimpleStringProperty property = new SimpleStringProperty();                   property.bindBidirectional(cellData.getValue().valutaProperty,  new SimpleDateFormat("dd.MM.yyyy", Locale.GERMAN));                   return property;                }); 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!