Riempire una TableView da databse in JavaFX

Mattepuffo's logo
Riempire una TableView da databse in JavaFX

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!


Condividi

Commentami!