Search code examples
javafxjavafx-8uitableviewcellrenderer

JavaFX : data isn't displayed in tableview's column when trying to use cellfactory


I want to display data in tableview's column with custom rendering. I tried to adapt this tuto to my need.

Problem : In the code example below, when I use the setCellFactory() method, the data in the corresponding column isn't displayed.

You can comment or uncomment the delimited section to see what happen in controller class.

Main class

public class CellFactory extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        AnchorPane root = FXMLLoader.load(CellFactory.class.getResource("CellFactory_Layout.fxml"));
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.setTitle("CellFactory EXAMPLE");
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Model class

public class Fruit {
    private final SimpleStringProperty name;
    private final SimpleIntegerProperty weight;

    public Fruit(String name, int weight){
        this.name = new SimpleStringProperty(name);
        this.weight = new SimpleIntegerProperty(weight);
    }

    public String getName() {return this.name.get();}
    public void setName(String v) {this.name.set(v);}
    public SimpleStringProperty nameProperty() {return this.name;}

    public int getWeight() {return this.weight.get();}
    public void setWeight(int v) {this.weight.set(v);}
    public SimpleIntegerProperty weightProperty() {return this.weight;}
}

Controller class

public class CellFactory_Controller implements Initializable {
    @FXML private TableView<Fruit> fruit_tbl;
    @FXML private TableColumn<Fruit, String> name_cln;
    @FXML private TableColumn<Fruit, Integer> weight_cln;

    // array with table data
    final ObservableList<Fruit> data = FXCollections.observableArrayList();

    public CellFactory_Controller() {
        // some data
        this.data.add(new Fruit("banana", 120));
        this.data.add(new Fruit("apple", 150));
        this.data.add(new Fruit("coconut", 500));
        this.data.add(new Fruit("orange", 200));
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        this.name_cln.setCellValueFactory(new PropertyValueFactory<>("name"));
        this.weight_cln.setCellValueFactory(new PropertyValueFactory<>("weight"));
        this.weight_cln.setCellValueFactory(cellData -> cellData.getValue().weightProperty().asObject());

        // comment or uncomment to see what happen
        ///////////////////////////////////////////////////////////////////////
        this.weight_cln.setCellFactory(column -> new TableCell<Fruit, Integer>() {
            @Override
            protected void updateItem(Integer item, boolean empty) {
                super.updateItem(item, empty);

                if (item == null || empty) {
                    setText(null);
                    setStyle("");
                } else {
                    if (item < 10) {
                        setTextFill(Color.CHOCOLATE);
                    } else {
                        setTextFill(Color.BLACK);
                        setStyle("");
                    }
                }
            }
        });
        ///////////////////////////////////////////////////////////////////////

        this.fruit_tbl.setItems(this.data);
    }
}

FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="CellFactory.CellFactory_Controller">
   <children>
      <TableView fx:id="fruit_tbl" layoutX="189.0" layoutY="93.0" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <columns>
          <TableColumn fx:id="name_cln" prefWidth="471.0" text="FRUIT" />
            <TableColumn fx:id="weight_cln" prefWidth="75.0" text="WEIGHT" />
        </columns>
         <columnResizePolicy>
            <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
         </columnResizePolicy>
      </TableView>
   </children>
</AnchorPane>

Question : From my code example, how can I use custom cell renderer properly (with int data type) to display my data ?


Solution

  • you forgot to add the following statement:

    setText(String.valueOf(item));
    

    So, your setCellFactory() method should look like the following:

    this.weight_cln.setCellFactory(column -> new TableCell<Fruit, Integer>() {
            @Override
            protected void updateItem(Integer item, boolean empty) {
                super.updateItem(item, empty);
    
                if (item == null || empty) {
                    setText(null);
                   setStyle("");
                } else {
                   setText(String.valueOf(item));
                    if (item < 200) {
    
                        setTextFill(Color.CHOCOLATE);
    
    
                    } else {
    
                        setTextFill(Color.BLACK);
    
                    }
                }
            }
        });