issue with this tutorial:Populate a tableview using database in JavaFX - java

I get a nullpointerxception when following this tutorial:
Populate a tableview using database in JavaFX .
I modified it to make it simpler and fit my needs:
Instead of Usermaster, I have Person object.
while(rs.next()){
Person per = new Person();
per.ClientID.set(rs.getInt(1));
per.FirstName.set(rs.getString(2));
per.LastName.set(rs.getString(3));
The code stops at per.ClientID.set(rs.getInt(1)); due to nullpointerxception.
If I make system.out.println(rs.getInt(1)) (or any other column), I get the value... But it appears that I can't pass it to my object per.
All Person object vars are SimpleString/IntergerProperty type, as shown in the tutorial.
Can someone help me to identify the mistake I made in coding this?
Thank you
**Answer: need to initialize values.
Now I have no errors, but my table is not populating...
Full code:
a) Main App
package tableview;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MainApp extends Application {
public static void main(String[] args) {
// TODO Auto-generated method stub
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("view/FXMLTable.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Model Class:
package tableview.model;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
public SimpleIntegerProperty ClientID = new SimpleIntegerProperty();
public SimpleStringProperty FirstName = new SimpleStringProperty();
public SimpleStringProperty LastName = new SimpleStringProperty();
public SimpleIntegerProperty getClientID() {
return ClientID;
}
public SimpleStringProperty getFirstname() {
return FirstName;
}
public SimpleStringProperty getLastName() {
return LastName;
}
public IntegerProperty clientIDProperty(){
return ClientID;
}
public StringProperty firstNameProperty(){
return FirstName;
}
public StringProperty lastNameProperty(){
return LastName;
}
}
Controller Class:
package tableview.view;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import tableview.model.Person;
public class FXMLTableController{
#FXML
public TableView<Person> tableview ;
#FXML
private TableColumn<Person, Number> clientIdColumn;
#FXML
private TableColumn<Person, String> firstNameColumn;
#FXML
private TableColumn<Person, String> lastNameColumn;
#FXML
private void initialize() {
assert tableview != null : "fx:id=\"tableview\" was not injected: check your FXML file 'UserMaster.fxml'.";
clientIdColumn.setCellValueFactory(cellData -> cellData.getValue().
clientIDProperty());
firstNameColumn.setCellValueFactory(cellData -> cellData.getValue()
.firstNameProperty());
lastNameColumn.setCellValueFactory(cellData -> cellData.getValue()
.lastNameProperty());
buildData();
}
private ObservableList<Person> data;
public void buildData(){
data = FXCollections.observableArrayList();
Connection con = null;
try {
Class.forName("org.sqlite.JDBC");
con = DriverManager.getConnection("jdbc:sqlite:tableviewdb.db");
String SQL = "Select * from INFO";
ResultSet rs = con.createStatement().executeQuery(SQL);
while(rs.next()){
Person per = new Person();
per.ClientID.set(rs.getInt("CLIENTID"));
per.FirstName.set(rs.getString("FIRSTNAME"));
per.LastName.set(rs.getString("LASTNAME"));
data.add(per);
}
tableview = new TableView<Person>();
tableview.setItems(data);
System.out.println(tableview.getItems().get(1).ClientID);
}
catch(Exception e){
e.printStackTrace();
System.out.println("Error on Building Data");
}
}
}

ClientID is null. You didn't initialize it.
If it's a property, you should create the proper getter and setters for it and not use the property directly. Besides you should never use 1, 2, etc in the ResultSet's getter. It's better practice to use the column names.

Related

How to fill JavaFX ChoiceBox with seprate Enum Class?

I am trying to create a JavaFX program to manage a production line. I am working with a database so that the user can populate a database with TextField and ChoiceBox. I am having trouble filling a ChoiceBox from an Enum class that I have created.
It is expected that my ChoiceBox is populated with items from my Enum class, however, the ChoiceBox is staying blank. The code is compiling.
Before you refer me to this link, I have tried using the advice in that discussion, but I am unable to wrap my head around it. That discussion does not help because I am not sure where they are trying to populate their ComboBox. Also, cbxStatus.getItems().setAll(Status.values()); is not working for me (I might be applying it incorrectly).
My Enum class:
package sample;
public enum ItemType {
AUDIO("AU"),
VISUAL("VI"),
AUDIOMOBILE("AM"),
VISUALMOBILE("VM");
final String itemType;
ItemType(String itemType) {
this.itemType = itemType;
}
public String getItemType() {
return itemType;
}
}
My Controller class:
package sample;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextField;
import java.sql.SQLException;
public class Controller {
#FXML
private TextField productName;
#FXML
private TextField productManufacturer;
#FXML
private ChoiceBox<ItemType> itemType = new ChoiceBox<>();
private DatabaseManager databaseManager = new DatabaseManager();
public Controller() throws SQLException {
}
#FXML
public void initialize() {
itemType.getItems().setAll(ItemType.values());
}
public void addProduct() {
String name = productName.getText();
String manufacturer = productManufacturer.getText();
String type = itemType.toString();
databaseManager.insert(type, manufacturer, name);
System.out.println("Button Pressed");
}
public void recordProduction(ActionEvent actionEvent) {
System.out.println("Button Pressed");
}
}
Lastly, once the ChoiceBox is populated, I need to capture the user's choice to input into my database. Something like String type = itemType.toString();.
I think you are missing the obvious and thinking the new thing, the Enum is the problem.
#FXML
private ChoiceBox<ItemType> itemType = new ChoiceBox<>();
Your controller's field has access to one ChoiceBox instance and the one on the form is a different one. You never added your items to the choicebox you interact with.

JavaFX bind choicebox to a property in a collection

With JavaFX, what is the best way to bind ChoiceBox to properties of a collection?
In example below I try to bind ChoiceBox elements to name of an ObservableList beans. This works fine when items are added/removed but not when the property value name change.
I was hoping there is a clean and simple solution to this but haven't yet found any example of it...
The class ExampleBean2 in deliberately not implemented with properties since that object may correspond to a external model class out of my control.
package com.playground;
import org.controlsfx.control.PropertySheet;
import org.controlsfx.property.BeanPropertyUtils;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class BindingPlayGround extends Application{
public static void main(String[] args) {
launch();
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("FXPlayGround");
Parent content = createContentPane();
Scene scene = new Scene(content, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
protected Parent createContentPane() {
ObservableList<BeanExample2> beans = FXCollections.observableArrayList();
ObservableList<PropertySheet> sheets = FXCollections.observableArrayList();
ListView<PropertySheet> listView = new ListView<PropertySheet>(sheets);
Button addBeanButton = new Button("Add Bean");
addBeanButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
BeanExample2 e = new BeanExample2();
e.setName("Name-not-set");
PropertySheet propertySheet = new PropertySheet(BeanPropertyUtils.getProperties(e));
sheets.add(propertySheet);
beans.add(e);
}
});
VBox vBar = new VBox();
vBar.getChildren().add(listView);
vBar.getChildren().add(addBeanButton);
ObservableList<BeanExample2> names = FXCollections.observableArrayList(new Callback<BeanExample2, Observable[]>() {
#Override
public Observable[] call(BeanExample2 param) {
return new Observable[]{new SimpleStringProperty(param, "name")};
}
});
Bindings.bindContent(names, beans);
Button addChoiceBoxButton = new Button("Add ChoiceBox");
addChoiceBoxButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
ChoiceBox<BeanExample2> choiceBox = new ChoiceBox<BeanExample2>(names);
vBar.getChildren().add(choiceBox);
}
});
vBar.getChildren().add(addChoiceBoxButton);
return vBar;
}
static class BeanExample2 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "BeanExample2{" +
"name='" + name + '\'' +
'}';
}
}
}
Here
ObservableList<BeanExample2> names = FXCollections.observableArrayList(new Callback<BeanExample2, Observable[]>() {
#Override
public Observable[] call(BeanExample2 param) {
return new Observable[]{new SimpleStringProperty(param, "name")};
}
});
you're creating a new property to listen to for updates that cannot be referenced except from the value returned by the call method. The only relationship between the BeanExample2 instance and the SimpleStringProperty is that the BeanExample2 instance is used as bean for the property, which has no effect besides being available via the getBean() method of the property. The value of the property is never assigned let alone modified on a change of the BeanExample2 instance.
To properly trigger updates in the ObservableList, you need to make sure the element in the array returned by the above method is actually notified of updates. Usually you add the property to the class itself:
public static class BeanExample2 {
public final String getName() {
return this.name.get();
}
private final StringProperty name = new SimpleStringProperty();
public final void setName(String value) {
this.name.set(value);
}
#Override
public String toString() {
return "BeanExample2{"
+ "name='" + name.get() + '\''
+ '}';
}
public final StringProperty nameProperty() {
return this.name;
}
}
And return an array containing the property from the Callback
ObservableList<BeanExample2> names = FXCollections.observableArrayList(new Callback<BeanExample2, Observable[]>() {
#Override
public Observable[] call(BeanExample2 param) {
return new Observable[]{param.nameProperty()};
}
});
Note that currently there seems to be a bug in ChoiceBox that adds entries for every intermediate value to the ChoiceBox.
ComboBox does not have this issue and could be used instead of a ChoiceBox.

Bind ComboBox#itemsProperty to Map#keySet

For what I am doing, I need to set the members of a javafx.scene.control.ComboBox to the members of a Map#keySet() Set.
The options available in the ComboBox need to update as the keys of the Map are updated. (Basically, I want to use the ComboBox to select members from the Map, which WILL be updated at runtime.)
Unfortunately, neither ComboBox#itemsProperty().bind(ObservableValue<>) nor ComboBox#itemsProperty().set(ObservableList<>) will take a Set<>, so the direct route of connecting the itemsProperty to the Map#keySet doesn't work.
Basically:
How can I make it so the ComboBox's items are the members of a Map's keySet?
Again, the behavior that I need is that the ComboBox's items will reflect the KeySet of my Map. (The Map can be any implementation of Map.)
EDIT: The problem seems to be creating an ObservableList out of a Collection -- in this case a Set -- without making it just a copy, but rather a reference to the Set, in order that the ObservableList will reflect the Set's contents.
If you have an ObservableMap, you can add a listener to it. For example:
ComboBox<String> comboBox = ... ;
ObservableMap<String, Something> map = ... ;
map.addListener((MapChangeListener.Change<? extends String, ? extends Something> c) ->
comboBox.getItems().setAll(map.keySet()));
You can also do this with a binding, though I don't think it's any cleaner:
comboBox.itemsProperty().bind(Bindings.createObjectBinding(() ->
FXCollections.observableArrayList(map.keySet()),
map);
Here's a SSCCE, demonstrating both techniques:
import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableMap;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class BindItemsToKeySet extends Application {
#Override
public void start(Stage primaryStage) {
ObservableMap<Integer, Item> itemLookupById = FXCollections.observableHashMap();
ComboBox<Integer> listenerCombo = new ComboBox<>();
ComboBox<Integer> bindingCombo = new ComboBox<>();
itemLookupById.addListener((MapChangeListener.Change<? extends Integer, ? extends Item> c) ->
listenerCombo.getItems().setAll(itemLookupById.keySet())
);
bindingCombo.itemsProperty().bind(Bindings.createObjectBinding(() ->
FXCollections.observableArrayList(itemLookupById.keySet()),
itemLookupById));
TextField textField = new TextField();
textField.setOnAction(e -> {
if (textField.getText().isEmpty()) {
return ;
}
Item item = new Item(textField.getText());
itemLookupById.put(item.getId(), item);
textField.clear();
});
textField.setTooltip(new Tooltip("Type an item name and press enter"));
VBox root = new VBox(10,
textField,
listenerCombo,
bindingCombo);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
primaryStage.setScene(new Scene(root, 250, 350));
primaryStage.show();
}
public static class Item {
private final int id ;
private final String name ;
private final static AtomicInteger nextID = new AtomicInteger(1000);
public Item(String name) {
this.id = nextID.incrementAndGet();
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
public static void main(String[] args) {
launch(args);
}
}

JavaFX: TableView row selection

I am working on a java/Javafx project for the first time and i have a TableView with multiple column (name, prename, age...) to present my data and I need the user to be able to select a single row and give me everytime all anformation about the person(Other columns) even when he click at another column but I haven't been able to find the right way to do it.
When i select a row my code give everytime the value of the cell i click on, but i need other informations to search with in my SQLite data base and work on it (Delete/edit this person..)
Here is the code that i use:
...//rest of code
#Override
public void initialize(URL location, ResourceBundle resources) {
private TableView<Student> tbl_elev=new TableView<Student>();
...
tbl_elev.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Object>() {
#Override
public void changed(ObservableValue<?> observableValue, Object oldValue, Object newValue) {
//Check whether item is selected and set value of selected item to Label
if (tbl_elev.getSelectionModel().getSelectedItem() != null) {
TableViewSelectionModel<Student> selectionModel = tbl_elev.getSelectionModel();
ObservableList<?> selectedCells = selectionModel.getSelectedCells();
#SuppressWarnings("unchecked")
TablePosition<Object, ?> tablePosition = (TablePosition<Object, ?>) selectedCells.get(0);
Object val = tablePosition.getTableColumn().getCellData(newValue);
System.out.println("Selected Value " + val);
}
}
});
}
... //rest of code
I am waiting for your suggestions and ideas, i dont mind if you suggest another approach because this may be uncompatible (taken from internet) Please if you need any other part of the code just comment, i don't put it all because it is too long to read.. (Sorry of my bad english)
If you specify that the ChangeListener parameters are of type Student you can get use the instance methods from that object:
Here's a Minimal, Complete, and Verifiable example:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class SSCCE extends Application {
#Override
public void start(Stage stage) {
VBox root = new VBox();
TableView<Student> studentsTable = new TableView<Student>();
HBox studentBox = new HBox();
Label studentHeader = new Label("Student: ");
Label studentInfo = new Label("");
studentBox.getChildren().addAll(studentHeader, studentInfo);
root.getChildren().addAll(studentsTable, studentBox);
// Prepare the columns
TableColumn<Student, String> firstNameCol = new TableColumn<Student, String>(
"First name");
firstNameCol.setCellValueFactory(cellData -> cellData.getValue()
.firstNameProperty());
TableColumn<Student, String> lastNameCol = new TableColumn<Student, String>(
"Last name");
lastNameCol.setCellValueFactory(cellData -> cellData.getValue()
.lastNameProperty());
studentsTable.getSelectionModel().selectedItemProperty()
.addListener(new ChangeListener<Student>() {
// Here's the key part. See how I specify that the
// parameters are of type student. Now you can use the
// instance methods from Student.
#Override
public void changed(
ObservableValue<? extends Student> observable,
Student oldValue, Student newValue ) {
studentInfo.setText(newValue.getFirstName() + " "
+ newValue.getLastName());
// If you want to get the value of a selected student cell at
// anytime, even if it hasn't changed. Just do e.g.
// studentsTable.getSelectionModel().getSelectedItem().getFirstName()
}
});
studentsTable.getColumns().setAll(firstNameCol, lastNameCol);
// Some mock Student objects
Student student1 = new Student("Eric", "Smith");
Student student2 = new Student("Brad", "Jones");
Student student3 = new Student("Logan", "Thorpe");
// Fill the table with students.
studentsTable.getItems().addAll(student1, student2, student3);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
// The student class. In this case an inner class to simplify the example. But generally you should never use inner classes.
class Student {
private StringProperty firstName;
private StringProperty lastName;
public Student(String firstName, String lastName) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public StringProperty lastNameProperty() {
return lastName;
}
}
}
After too many failed attempts and thanks to #Jonatan 's answer the code after i compelete some missing words should be like this:
...//rest of code
#Override
public void initialize(URL location, ResourceBundle resources) {
private TableView<Student> tbl_elev=new TableView<Student>();
...
tbl_elev.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Student>() {
// Here's the key part. See how I specify that the
// parameters are of type student. Now you can use the
// instance methods from Student.
#Override
public void changed(ObservableValue<? extends Student> observable,Student oldValue, Student newValue){
if(newValue!=null){
System.out.println(newValue.getName() + " "+ newValue.getPrename()+" "+newValue.getNaiss());
}
//you can add any other value from Student class via getter(getAdr,getMail,...)
}
});
}
... //rest of code
Output example:
Jonatan stenbacka 2015-09-11
Those value are ready for use to fetch the data base and specify the needed row in it to work on.
Hope that this help someone one day.
thanks...

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

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..
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.
For the future people and Java 11 you can may fix this with that:
For example, if the Person class is in the com.foo package in the foo.app module, the module-info.java might look like this:
module foo.app {
opens com.foo to javafx.base;
}
or:
module foo.app {
opens com.foo; <-- place for with your class
}
https://openjfx.io/javadoc/11/javafx.controls/javafx/scene/control/cell/PropertyValueFactory.html

Categories

Resources