Issue
I am just trying to see if I am able to get data from MS Access into a table using a TableView in FXML, but none of the data from my table in MS Access appears in the TableView. However, if I display just the content of my table as a message dialogue, all the correct information appears. Please can someone show me where I am going wrong.
I watched this Youtube video 1, and followed it step by step, as well as other sources, but nothing fixes my issue.
@FXML
private TableView<modelTable> table;
@FXML
private TableColumn<modelTable, StringProperty> colStudentName;
@FXML
private TableColumn<modelTable, StringProperty> colSurname;
@FXML
private TableColumn<modelTable, IntegerProperty> colGrade;
@FXML
private TableColumn<modelTable, StringProperty> colEmail;
ObservableList<modelTable> list = FXCollections.observableArrayList();
@Override
public void initialize(URL url, ResourceBundle rb) {
try {
Connection connection = DBConnect.getConnection();
ResultSet rs = connection.createStatement().executeQuery("SELECT * FROM data");
while (rs.next()) {
//If I run the JOptionPane on its own, all the data is displayed
//JOptionPane.showMessageDialog(null, (rs.getString("StudentName")+ "\t" + rs.getString("Surname") + "\t" + rs.getInt("Grade") + "\t" + rs.getString("Email")));
list.add(new modelTable(rs.getString("StudentName"), rs.getString("Surname"), rs.getInt("Grade"), rs.getString("Email")));
}
} catch (SQLException ex) {
Logger.getLogger(TableController.class.getName()).log(Level.SEVERE, null, ex);
}
colStudentName.setCellValueFactory(new PropertyValueFactory<>("StudentName"));
colSurname.setCellValueFactory(new PropertyValueFactory<>("Surname"));
colGrade.setCellValueFactory(new PropertyValueFactory<>("Grade"));
colEmail.setCellValueFactory(new PropertyValueFactory<>("Email"));
table.setItems(list);
}
}
public class modelTable {
private StringProperty colName, colSurname, colEmail;
private IntegerProperty colGrade;
public modelTable(String colName, String colSurname, int colGrade, String colEmail) {
this.colName = new SimpleStringProperty(colName);
this.colSurname = new SimpleStringProperty(colSurname);
this.colEmail = new SimpleStringProperty(colEmail);
this.colGrade = new SimpleIntegerProperty(colGrade);
}
public String getColName() {
return colName.get();
}
public void setColName(String colName) {
this.colName.set(colName);
}
public String getColSurname() {
return colSurname.get();
}
public void setColSurname(String colSurname) {
this.colSurname.set(colSurname);
}
public String getColEmail() {
return colEmail.get();
}
public void setColEmail(String colEmail) {
this.colEmail.set(colEmail);
}
public int getColGrade() {
return colGrade.get();
}
public void setColGrade(int colGrade) {
this.colGrade.set(colGrade);
}
}
public class DBConnect {
public static Connection getConnection() throws SQLException{
Connection connection = DriverManager.getConnection("jdbc:ucanaccess://C://Users//Huzaifah//Desktop//School work 2019//testing table.accdb");
return connection;
}
I expect the data to be in the TableView when I run the program, but it's empty. No error message is given, only an empty table.
I tried using this same database in just a simple program without a TableView and it works perfectly fine.
Solution
The problem is with your how you're setting your CellValueFactory
for each column:
colStudentName.setCellValueFactory(new PropertyValueFactory<>("StudentName"));
colSurname.setCellValueFactory(new PropertyValueFactory<>("Surname"));
colGrade.setCellValueFactory(new PropertyValueFactory<>("Grade"));
colEmail.setCellValueFactory(new PropertyValueFactory<>("Email"));
The properties you're specifying (StudentName
, Surname
, etc) do not match any exposed properties in your modelTable
class. In modelTable
, all your properties begin with "col" for some reason.
As a side note, Java naming conventions suggest that class names begin with a capital letter...
You should refactor your ModelTable
class to use properties that are visible by your TableView
. You should change your property names to be more reflective of the data. Adding a "col" prefix is confusing and unnecessary as your model class should not care or be aware of how it is going to be displayed:
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
class Scratch {
private final StringProperty name = new SimpleStringProperty();
private final StringProperty surname = new SimpleStringProperty();
private final StringProperty email = new SimpleStringProperty();
private final IntegerProperty grade = new SimpleIntegerProperty();
public modelTable(String colName, String colSurname, int colGrade, String colEmail) {
this.name.set(colName);
this.surname.set(colSurname);
this.email.set(colEmail);
this.grade.set(colGrade);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public String getSurname() {
return surname.get();
}
public StringProperty surnameProperty() {
return surname;
}
public void setSurname(String surname) {
this.surname.set(surname);
}
public String getEmail() {
return email.get();
}
public StringProperty emailProperty() {
return email;
}
public void setEmail(String email) {
this.email.set(email);
}
public int getGrade() {
return grade.get();
}
public IntegerProperty gradeProperty() {
return grade;
}
public void setGrade(int grade) {
this.grade.set(grade);
}
}
Note how we now declare the properties as final and initialize them as class fields. We can do this because we may change the value of a property, but will not change the property itself.
Also notice that we are adding a getter for each property. This allows us to refer to them directly in the controller when setting each CellValueFactory
.
Then you need to update your setCellValueFactory()
methods to use the new property names. I do not recommend using reflection (creating a new PropertyValueFactory()
, however), as with your exposed properties, that is not necessary.
Instead, just pass a reference to the properties directly:
colStudentName.setCellValueFactory(features -> features.getValue().nameProperty());
colSurname.setCellValueFactory(features -> features.getValue().surnameProperty());
colEmail.setCellValueFactory(features -> features.getValue().emailProperty());
colGrade.setCellValueFactory(features -> features.getValue().gradeProperty());
Answered By - Zephyr