cannot convert from String to ObservableValue<String>

JOSEMAFUEN picture JOSEMAFUEN · May 19, 2015 · Viewed 14.7k times · Source

I'm making a program to manage and show data about airports, their flights and so on. The fact is that I have a tableView (in javafx) with several tableColumns, and I want to show some information (destiny, origin, company, etc) on each column so I typed this:

@FXML
private TableColumn<Flight, String> destinoCol;

@FXML
private TableColumn<Flight, String> numCol;

@FXML
private MenuButton aeropuerto;

@FXML
private MenuButton tipo;

@FXML
private Button filtrar;

@FXML
private TableColumn<Flight, LocalTime> horaCol;

@FXML
private Button este;

@FXML
private DatePicker fecha;

@FXML
private TableColumn<Flight, String> origenCol;

@FXML
private Label retrasoLabel;

@FXML
private ImageView companiaImg;

@FXML
private VBox detalles;

@FXML
private Button todos;

@FXML
private ImageView avionImg;

@FXML
private Label tipoLabel;

private mainVuelos m;
private List<Airport> aeropuertos;
private Data data;
@FXML
void initialize() {
    data = Data.getInstance();
    aeropuertos = data.getAirportList();
    List<MenuItem> ItemAeropuertos = new LinkedList<MenuItem>();
    for (int i = 0; i < aeropuertos.size(); i++) {
        MenuItem item = new MenuItem(aeropuertos.get(i).getName());
        item.setOnAction((event) -> cambiarAer(event));
        ItemAeropuertos.add(item);
    }
    aeropuerto.getItems().setAll(ItemAeropuertos);
    destinoCol.setCellValueFactory(cellData -> cellData.getValue().getDestiny());
}

The method getDestiny(), as it says returns the destiny of a specific flight as a String so obviously I cannot use the last instruction, it says

cannot convert from String to ObservableValue<String>

but I don't really know how to solve it in order to be able to show the destinies on that column.

Answer

James_D picture James_D · May 19, 2015

According to the Javadocs, setCellValueFactory(...) expects a Callback<CellDataFeatures<Flight, String>, ObservableValue<String>>, i.e a function that takes a CellDataFeatures<Flight, String> as its parameter, and results in an ObservableValue<String>.

As the error message says, your function evaluates to a String (cellData.getValue().getDestiny()), which is not the correct type.

You have two choices, depending on your actual requirements.

Either you can create something on the fly that is of the correct type: the easiest thing to use is a ReadOnlyStringWrapper:

destinoCol.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getDestiny()));

This will display the correct value, but won't be nicely "wired" to the property of the flight object. If your table is editable, edits won't automatically propagate back to the underlying object, and changes to the underlying object from elsewhere won't automatically update in the table.

If you need this functionality (and this is probably a better approach anyway), you should implement your model class Flight to use JavaFX properties:

public class Flight {

    private final StringProperty destiny = new SimpleStringProperty();

    public StringProperty destinyProperty() {
        return destiny ;
    }

    public final String getDestiny() {
        return destinyProperty().get();
    }

    public final void setDestiny(String destiny) {
        destinyProperty().set(destiny);
    }

    // similarly for other properties...
}

and then you can do

destinoCol.setCellValueFactory(cellData -> cellData.getValue().destinyProperty());