Riempire una TableView da databse in JavaFX
Ho deciso di eseguire il porting di un mio vecchio programma scritto in Java, da Swing a JavaFX.
Uno dei problemi che ho riscontrato è come rimpire una TableView da database.
Ovviamente le tabelle funzionano in maniera completamente diverse da Swing.
Qua vediamo proprio questo; però tenete in considerazione che:
- come db uso SQLite (anche se cambia poco)
- non spiegherò per filo e per segno come usare e installare il driver JDBC per SQLite; vi posterò direttamente il codice
Cominciamo dal db; la tabella che interroghiamo ha questa struttura:
0|id|INTEGER|1||1
1|title|VARCHAR|1||0
2|released|VARCHAR|0||0
3|genre|VARCHAR|0||0
4|director|VARCHAR|0||0
5|writer|VARCHAR|0||0
6|actors|VARCHAR|0||0
7|plot|VARCHAR|0||0
8|poster|VARCHAR|0||0
9|runtime|VARCHAR|0||0
10|imdb_id|VARCHAR|0||0
Bene, questa la classe (Singleton) che si connette al db e interroga la tabella:
public class DbManager {
private static Connection conn;
private DbManager() {
}
public static DbManager getInstance() {
return DbManagerHolder.INSTANCE;
}
private static class DbManagerHolder {
private static final DbManager INSTANCE = new DbManager();
}
public Connection getConn() throws ClassNotFoundException,
SQLException, UnsupportedEncodingException {
Class.forName("org.sqlite.JDBC");
return conn = DriverManager.getConnection("jdbc:sqlite:films.sqlite");
}
public ObservableList getFilms() throws ClassNotFoundException,
SQLException, IOException {
conn = DbManager.getInstance().getConn();
ArrayList list = new ArrayList<>();
try (
PreparedStatement cstmt =
conn.prepareStatement("SELECT * FROM film ORDER BY title");
ResultSet rs = cstmt.executeQuery()
) {
while (rs.next()) {
list.add(
new Film(
rs.getString("id"),
rs.getString("title"),
rs.getString("released"),
rs.getString("runtime"),
rs.getString("imdb_id")
)
);
}
}
ObservableList obl = FXCollections.observableArrayList(list);
return obl;
}
}
Il metodo ritorna una ObservableList.
Questa la classe POJO che fa da contenitore a oggetti Film:
import javafx.beans.property.SimpleStringProperty;
public class Film {
private SimpleStringProperty id;
private SimpleStringProperty title;
private SimpleStringProperty released;
private SimpleStringProperty genre;
private SimpleStringProperty director;
private SimpleStringProperty writer;
private SimpleStringProperty actors;
private SimpleStringProperty plot;
private SimpleStringProperty poster;
private SimpleStringProperty runtime;
private SimpleStringProperty imdbid;
public Film(String id, String title, String released, String runtime, String imdbid) {
this.id = new SimpleStringProperty(id);
this.title = new SimpleStringProperty(title);
this.released = new SimpleStringProperty(released);
this.runtime = new SimpleStringProperty(runtime);
this.imdbid = new SimpleStringProperty(imdbid);
}
public String getId() {
return id.get();
}
public void setId(String id) {
this.id.set(id);
}
public String getTitle() {
return title.get();
}
public void setTitle(String title) {
this.title.set(title);
}
public String getReleased() {
return released.get();
}
public void setReleased(String released) {
this.released.set(released);
}
public String getGenre() {
return genre.get();
}
public void setGenre(String genre) {
this.genre.set(genre);
}
public String getDirector() {
return director.get();
}
public void setDirector(String director) {
this.director.set(director);
}
public String getWriter() {
return writer.get();
}
public void setWriter(String writer) {
this.writer.set(writer);
}
public String getActors() {
return actors.get();
}
public void setActors(String actors) {
this.actors.set(actors);
}
public String getPlot() {
return plot.get();
}
public void setPlot(String plot) {
this.plot.set(plot);
}
public String getPoster() {
return poster.get();
}
public void setPoster(String poster) {
this.poster.set(poster);
}
public String getRuntime() {
return runtime.get();
}
public void setRuntime(String runtime) {
this.runtime.set(runtime);
}
public String getImdbid() {
return imdbid.get();
}
public void setImdbid(String imdbid) {
this.imdbid.set(imdbid);
}
}
Abbiamo messo tutti i campi, anche se poi nella tabella ne visualizzeremo solo alcuni; e questo lo potete vedere direttamente dal costruttore.
Nel nostro controller, che viene richiamato dal layout, abbiamo questo:
public class ControllerMain {
private DbManager db = DbManager.getInstance();
@FXML
TableView tblFilm;
public void initialize() {
try {
tblFilm.getColumns().setAll(TableColumns.setcols());
tblFilm.setItems(db.getFilms());
} catch (ClassNotFoundException | IOException | SQLException ex) {
}
}
}
Le colonne le impostiamo da una classe apposita con metodo statico, che è questa:
public class TableColumns {
public static ArrayList setcols() {
String[] arrCols = {"ID", "TITLE", "RELEASED", "RUNTIME", "IMDBID"};
ArrayList tbc = new ArrayList<>();
for (int i = 0; i < arrCols.length; i++) {
TableColumn tc = new TableColumn(arrCols[i]);
tc.setCellValueFactory(
new PropertyValueFactory<Film, String>(arrCols[i].toLowerCase())
);
tbc.add(tc);
}
return tbc;
}
}
Ovviamente potete modificare questa parte; la cosa importante che però dovete notare, è che l'intestazione delle colonne corrisponde al nome dei campi della classe Film che vogliamo visualizzare.
La differenza sta solo nel maiuscolo / minuscolo.
Senza questa accortezza, vedevo le righe nella TableView, ma non venivano visualizzati i valori.
Fate qualche prova per capire meglio.
Infine il layout:
<BorderPane fx:id="uno" xmlns="http://javafx.com/javafx/8.0.112"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.mp.film.ControllerMain">
<top>
</top>
<left>
</left>
<center>
<TableView fx:id="tblFilm" BorderPane.alignment="CENTER">
</TableView>
</center>
</BorderPane>
Il codice è ripreso da un esempio reale funzionante (sto sviluppando giusto ora questo programmino).
Enjoy!
java javafx tableview jdbc sqlite observablelist
Commentami!