javafx.scene.control.TableColumn cannot be cast to javafx.scene.control.TableColumn$CellDataFeatures

Do Re picture Do Re · Sep 4, 2015 · Viewed 13.6k times · Source

I have a problem when it comes to filling a javafx tableview.

I am currently working on a GUI based event management tool (for university) and I am stuck trying to fill a Tableview list, that should be in the center of a border pane layout.

This is my code (its pretty long thought, its the main window function):

import java.sql.Date;
import java.sql.SQLException;
import java.util.List;

//--main imports--//
import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Label;
//--table imports--//
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.TableColumn;
import javafx.scene.text.Font;
import javafx.stage.Stage;

public class MainWindow extends Application {


private static Label tableHeadline;
private static TableView table;
private static TableColumn dateCol;
private static TableColumn nameCol;
private static TableColumn numberOfGuestsCol;
private static TableColumn locationCol;

private static BorderPane layout;

//This is just some test data, this is where the program crashes, I think
final static ObservableList<Event> data =  FXCollections.observableArrayList(
        new Event("Jacob", "Smith", 30, new Date(10000))
        );
//----------------------//

//--Private constants--//   
private static final String DATE = "Date";
private static final String NAME = "Name";
private static final String NUMBER_OF_GUESTS = "Number of guests";
private static final String LOCATION = "Location";
//---------------------//


/**The main method, launching the application*/
public static void main(String[] args) {
    try {
    //--launching the application with given arguments--//
    launch(args);}
    catch (Exception e) {e.printStackTrace();}
}

/**
 * The start-method, that is called first when 'launch' is used
 */
@Override
public void start(Stage primaryWindow) throws Exception {

    //--initialize all the objects in the window--//
    initializeObjects();

    //--get the layout--//
    initializeLayout();

    //--give functionality to the objects in the window--//
    functionalizeObjects();

    //--create the new scene--//
    Scene main = new Scene(layout);

    //--Giving the main window a title and bringing it up front--//
    primaryWindow.setMinHeight(DEFAULT_WIN_HEIGHT);
    primaryWindow.setMinWidth(DEFAULT_WIN_WIDTH);
    primaryWindow.setScene(main);
    primaryWindow.show();

    //TODO: on window close, save the content of the list to the db
    primaryWindow.setOnCloseRequest(null);
}


/**
 * Initializes all given elements of the main window by creating and naming them
 */
private static void initializeObjects () {
    //--table--//
    tableHeadline = new Label (TABLE_HEAD);
    tableHeadline.setFont(new Font ("Arial", 20));

    table = new TableView<>();

    table.setEditable(true);

    //--date column--//
    dateCol = new TableColumn<Event, Date>(DATE);
    dateCol.setCellFactory(
            new PropertyValueFactory<>("Date")
        );

    //--name column--//
    nameCol = new TableColumn<Event, String>(NAME);
    nameCol.setCellValueFactory(
            new PropertyValueFactory<>("name")
        );      

    //--numberOfGuests column--//
    numberOfGuestsCol = new TableColumn<Event, Integer>(NUMBER_OF_GUESTS);
    numberOfGuestsCol.setMinWidth(150);
    numberOfGuestsCol.setCellValueFactory(
            new PropertyValueFactory<>("Number of Guests")
        );

    //--location column--//
    locationCol = new TableColumn<Event, String>(LOCATION);
    locationCol.setCellValueFactory(
            new PropertyValueFactory<>("location")
        );

        table.setItems(data);
        table.getColumns().addAll(nameCol,locationCol,
                numberOfGuestsCol,dateCol);

    //TODO fill with data from the database
    //--end table--//
}

/**
 * Assign functionality to the elements of the main window
 */
private static void functionalizeObjects () {

    //--new... MenuItem--//
    newMItem.setOnAction(e -> {
        createReturn = CreatePopup.display();

        if (createReturn) {
            //--get the user input--//
            List<Object> toCreate = CreatePopup.getInput();

            //--add a new event according to the user input to the list--//
           //This is where new Events should be inserted, but I cannot test this as I do not come that far
            final ObservableList<Event>data = FXCollections.ObservableArrayList(
                    new Event(toCreate(0),toCreate(1),toCreate(2),toCreate(3))
                    );

            }
        }
    });

    });

}

/**
 * Initializes the layout of the main window
 */
private static void initializeLayout() {
    //--Create a new layout--//
    layout = new BorderPane();

    layout.setTop(menuBar);
    layout.setCenter(table);
}

public static class Event {
    private final SimpleStringProperty name;
    private final SimpleStringProperty location;
    private final SimpleIntegerProperty numberOfGuests;
    private final SimpleObjectProperty<Date> date;

    private Event(String name, String location, int numOfGuests, Date date) {
        this.name = new SimpleStringProperty(name);
        this.location = new SimpleStringProperty(location);
        this.numberOfGuests = new SimpleIntegerProperty(numOfGuests);
        this.date = new SimpleObjectProperty<Date>(date);
    }


    //--------//
    // Getter //
    //--------//

    public SimpleStringProperty getName() {
        return name;
    }

    public SimpleStringProperty getLocation() {
        return location;
    }

    public SimpleIntegerProperty getNumberOfGuests() {
        return numberOfGuests;
    }

    public SimpleObjectProperty<Date> getDate() {
        return date;
    }

}

}

This code will give me an error:

    Exception in Application start method
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: javafx.scene.control.TableColumn cannot be cast to javafx.scene.control.TableColumn$CellDataFeatures
    at javafx.scene.control.cell.PropertyValueFactory.call(PropertyValueFactory.java:98)
    at com.sun.javafx.scene.control.skin.TableRowSkin.getCell(TableRowSkin.java:87)
    at com.sun.javafx.scene.control.skin.TableRowSkin.getCell(TableRowSkin.java:53)
    at com.sun.javafx.scene.control.skin.TableRowSkinBase.createCell(TableRowSkinBase.java:698)
    at com.sun.javafx.scene.control.skin.TableRowSkinBase.recreateCells(TableRowSkinBase.java:692)
    at com.sun.javafx.scene.control.skin.TableRowSkinBase.init(TableRowSkinBase.java:146)
    at com.sun.javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:64)
    at javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:212)
    at javafx.scene.control.Control.impl_processCSS(Control.java:859)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1272)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1272)
    at javafx.scene.Parent.impl_processCSS(Parent.java:1272)
    at javafx.scene.control.Control.impl_processCSS(Control.java:855)
    at javafx.scene.Node.processCSS(Node.java:9056)
    at javafx.scene.Node.processCSS(Node.java:9049)
    at javafx.scene.Scene.doCSSPass(Scene.java:545)
    at javafx.scene.Scene.access$3600(Scene.java:159)
    at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2392)
    at com.sun.javafx.tk.Toolkit.lambda$runPulse$31(Toolkit.java:348)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:347)
    at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:374)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:510)
    at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
    at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$405(QuantumToolkit.java:319)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$50(GtkApplication.java:139)
    at java.lang.Thread.run(Thread.java:745)

I cannot think of any reason for this strange Error. I also searched pretty long now and tried pretty many things, but it still appears on startup.

Now I am counting on you, community, please help me!

Thanks in advance for reading the long post..

Answer

James_D picture James_D · Sep 4, 2015

You have

dateCol.setCellFactory(...);

instead of

dateCol.setCellValueFactory(...);

This is a good example of why you should not use raw types in your code, and should avoid API like PropertyValueFactory in favor of typesafe code.

I.e. you have

TableView table ;
TableColumn dateCol ;

when you should have something like

TableView<Event> table ;
TableColumn<Event, Date> dateCol ;

And then you can do

dateCol.setCellValueFactory(cellData -> cellData.getValue().getDate());

If you coded it this way, the compiler would have immediately picked up on your error.

As an aside (perhaps, another aside), you should really make your Event class follow the correct JavaFX Properties pattern, as described in the tutorial. You may see unexpected behavior if you don't.