I've created a TableView using Scene Builder as follows-
Here is the FXML code-
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="508.0" prefWidth="483.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="imran.jfx.application.Controller">
<children>
<TableView fx:id="tableview" layoutX="19.0" layoutY="94.0" prefHeight="402.0" prefWidth="443.0">
<columns>
<TableColumn fx:id="id" prefWidth="75.0" text="ID" />
<TableColumn fx:id="english" prefWidth="170.0" text="English" />
<TableColumn fx:id="bangla" prefWidth="197.0" text="Bangla" />
</columns>
</TableView>
<Button fx:id="showTableview" layoutX="188.0" layoutY="52.0" mnemonicParsing="false" onAction="#showTableData" text="Show Tables" />
</children>
</Pane>
I tried to connect with the database and tried to show data from the database to tableview. I tried to implement this things into Controller Class as follows-
package imran.jfx.application;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.util.Callback;
public class Controller implements Initializable{
private ObservableList<ObservableList> data;
@FXML
private TableView<?> tableview;
@FXML
private TableColumn<?, ?> id;
@FXML
private TableColumn<?, ?> english;
@FXML
private TableColumn<?, ?> bangla;
@FXML
private Button showTableview;
ResultSet result;
PreparedStatement doQuery;
Connection conn;
String query;
@Override
public void initialize(URL location, ResourceBundle resources)
{
try
{
Class.forName("org.sqlite.JDBC");
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
String url="jdbc:sqlite::resource:database/bn_words.db";
try
{
conn = DriverManager.getConnection(url);
}
catch (SQLException e) {
e.printStackTrace();
}
}
public void buildData()
{
data = FXCollections.observableArrayList();
try{
Class.forName("org.sqlite.JDBC");
String url="jdbc:sqlite::resource:database/bn_words.db";
conn = DriverManager.getConnection(url);
String SQL = "SELECT _id,en_word,bn_word from words";
ResultSet rs = conn.createStatement().executeQuery(SQL);
for(int i=0 ; i<rs.getMetaData().getColumnCount(); i++)
{
final int j = i;
TableColumn col = new TableColumn(rs.getMetaData().getColumnName(i+1));
col.setCellValueFactory(new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
tableview.getColumns().addAll(col);
System.out.println("Column ["+i+"] ");
}
while(rs.next()){
ObservableList<String> row = FXCollections.observableArrayList();
for(int i=1 ; i<=rs.getMetaData().getColumnCount(); i++){
row.add(rs.getString(i));
}
System.out.println("Row [1] added "+row );
data.add(row);
}
tableview.setItems(data);
}catch(Exception e){
e.printStackTrace();
System.out.println("Error on Building Data");
}
}
@FXML
void showTableData(ActionEvent event) {
tableview = new TableView();
buildData();
}
}
The problem is, it is showing error for the line tableview.setItems(data);
. I don't know the reason for this error. If I edit the line private TableView<?> tableview;
to private TableView tableview;
then it doesn't shows any error for the line tableview.setItems(data);
. Then the app runs well. But when I click on the button Show Tables, it doesn't show the data into the TableView, but it shows the data into console.
There also shown lots of warnings as follows-
Should I ignore these errors? How do I fix my problem?
No, do not ignore the warnings. The warnings are because you are using raw types for types that are "generic", i.e. parametrized. If you do this, you can end up with type mismatches that are not caught by the compiler. Using properly declared types and getting them correct will make your programs more robust.
TableView
, for example, is a generic type: it is declared as TableView<T>
. Here T
is a type parameter: you can (loosely speaking) think of T
as a variable that represents the type of the thing in each row of the table. When you create an actual TableView
, you have to specify what type that particular TableView
is going to hold. In your example each row is represented by an ObservableList
. Now, ObservableList
is also a generic type: it is declared as ObservableList<E>
, where E
represents the type of each element of the list. In your case, in the buildData()
method, you create an ObservableList<String>
for each row. Therefore, your table type is ObservableList<String>
, and so you should replace
@FXML
private TableView<?> tableView ;
with
@FXML
private TableView<ObservableList<String>> tableView ;
The items
belonging to a TableView<T>
are represented as an ObservableList<T>
. Since, for your table, T
is ObservableList<String>
, you need your items to be an ObservableList<ObservableList<String>>
(read this as "an observable list of observable lists of strings"). So you should replace
private ObservableList<ObservableList> data;
with
private ObservableList<ObservableList<String>> data ;
These changes should remove the compile error from tableView.setItems(data);
.
You should also fix the declarations of the TableColumn
s. TableColumn
is defined as TableColumn<S,T>
. Here S
is the type of the table (i.e. the type of each item representing a row in the table: it's the same as T
in the TableView
definition), and T
is the type of each value in a cell in the column. Each value in a cell, in all of your columns, is String
, so in buildData()
you should have:
TableColumn<ObservableList<String>, String> col = new TableColumn<>(rs.getMetaData().getColumnName(i+1));
(Note that since these are the columns you are adding to your table, it's not really clear why you also have columns defined in your FXML; that is kind of off-topic for the question you are asking though.)
All of this gets quite complex when you are using general lists as the data type for your table. Since in this you know how many columns are in your database, and what those columns represent, I very strongly encourage to make the table more specific by defining a class to represent the data in each row. I don't know what your application is, so I'll make a (probably incorrect) guess that it is doing some translation. So I would do
public class TranslatedWord {
private final StringProperty id = new SimpleStringProperty();
public StringProperty idProperty() {
return id ;
}
public final String getId() {
return idProperty().get();
}
public final void setId(String id) {
idProperty().set(id);
}
private final StringProperty english = new SimpleStringProperty();
public StringProperty englishProperty() {
return english ;
}
public final String getEnglish() {
return englishProperty().get();
}
public final void setEnglish(String english) {
englishProperty().set(english);
}
private final StringProperty bangla = new SimpleStringProperty();
public StringProperty banglaProperty() {
return bangla ;
}
public final String getBangla() {
return banglaProperty().get();
}
public final void setId(String bangla) {
banglaProperty().set(bangla);
}
}
Now you make a TableView<TranslatedWord>
and TableColumn<TranslatedWord, String>
, etc. Your data
becomes an ObservableList<TranslatedWord>
, and your buildData()
method has code like
while(rs.next()){
TranslatedWord word = new TranslatedWord();
word.setId(rs.getString("id"));
word.setEnglish(rs.getString("english"));
word.setBangla(rs.getString("bangla"));
System.out.println("Row [1] added "+row );
data.add(row);
}
Once you get used to this structure, you will find this a much easier style to maintain, as the types specify what they represent.
You also have lots of other things wrong in this code: as I said earlier you are creating the TableView
and TableColumn
s in FXML, but then you are creating new ones in the controller and manipulating those. Consequently, even if you fix the problems you actually asked about, you'll probably find it won't work the way you want until you fix those issues too. But getting rid of the compile errors and warnings is going to be a start...