Search code examples
javajavafxtableviewtablecolumn

How to define a cell's content based on the contents of an object's attribute using setCellFactory?


I've created a class called "ChatMessage" with 3 attributes:

a) timeOfMessage
b) sentOrReceived
c) message

and chat messages are stored inside an array of ChatMessages. I've defined a tableView, and 3 tableColumns (for a, b and c), like so:

// ------------------------
// Step 1: Define tableView
// ------------------------
@FXML private TableView<ChatMessage> tableViewAllMessages;

// ---------------------------
// Step 2: Define table's data
// ---------------------------
private ObservableList<ChatMessage> allMessagesList;

// --------------------------------
// Step 3: Define table's 3 columns
// --------------------------------
@FXML private TableColumn<ChatMessage, LocalDateTime> timeColumn;
@FXML private TableColumn<ChatMessage, Boolean> sentOrReceivedColumn;
@FXML private TableColumn<ChatMessage, String> messageColumn;

// ---------------------------------
// Step 4: Using setCellValueFactory
// ---------------------------------
timeColumn.setCellValueFactory(new PropertyValueFactory<ChatMessage,LocalDateTime>("dateTime"));
sentOrReceivedColumn.setCellValueFactory(new PropertyValueFactory<ChatMessage, Boolean>("sentOrReceived"));
messageColumn.setCellValueFactory(new PropertyValueFactory<ChatMessage,String>("message"));
tableViewAllMessages.setItems(allMessagesList);

Everything works fine! However, I would like to turn sentOrReceivedColumn (in Step 2), which currently of a boolean value, into a string value, based on the true/false it returns. Is there a way to make a cell write 'someStringA' when false and 'someStringB' when true? To be more specific, what do I need to change in here:

sentOrReceivedColumn.setCellValueFactory(new PropertyValueFactory<ChatMessage, Boolean>("sentOrReceived"));

or maybe add a line like this:

sentOrReceivedColumn.setCellFactory(/* But what Do I write here? */);

?


// Here is my ChatMessage Class:
public class ChatMessage {
    private Customer customer;
    private int messageNumber;
    private LocalDateTime dateTime;
    private String message;
    private boolean sentOrReceived;

    public ChatMessage(Customer customer, int messageNumber, LocalDateTime dateTime, String message, boolean sentOrReceived) {
        this.customer = customer;
        this.messageNumber = messageNumber;
        this.dateTime = dateTime;
        this.message = message;
        this.sentOrReceived = sentOrReceived;
    }
}

Solution

  • Thank you Slaw for your comment! It steered me in the right direction. I implemented my own factory that maps the value with just a lambda expression as you suggested. This was the answer I was looking for:

    col2_Nickname.setCellFactory(lambda -> new TableCell<ChatMessage, Boolean>() {
                @Override
                public void updateItem(Boolean sentOrReceived, boolean empty) {
                    super.updateItem(sentOrReceived, empty);
                    if (empty) {
                        setText(null);
                    }else{
                        setText(sentOrReceived ? "MyNickname" : "His/Her nickname");
                    }
                }
            });