LE TABELLE Le liste permettono di avere una sequenza di righe In alcune applicazioni è però necessario visualizzare le informazioni anche in colonne Nome Mario Franco Cognome Bianchi Rossi Indirizzo Telefono Via Roma, 12 059/1111111 Via Milano, 33 059/2222222 La libreria swing mette a disposizione un componente per la rappresentazione di informazioni in forma tabellare, implementato dalla classe JTable Ogni tabella implementata con JTable recupera i dati da rappresentare tramite un modello, istanza di una classe che implementa l’interfaccia TableModel Questa interfaccia mette a disposizione metodi per sapere quante righe/colonne servono, qual è il valore di ogni singola cella, se le celle sono editabili, ecc. Modello TableModel Vista JTable È disponibile anche una classe astratta, AbstractTableModel, che implementa la maggior parte dei metodi di TableModel, e lascia al programmatore da implementare solo i tre metodi: public int getRowCount(); public int getColumnCount(); public Object getValueAt(int row, int column); Cabri, Denti, Zambonelli - GRAFICA in JAVA - 69 ESEMPIO 20: LE TABELLINE Si vuole implementare la visualizzazione delle classiche tabelline che vengono imparate a memoria alle scuole elementari È quindi necessario: 1) Definire il modello dei dati 2) Definire la vista dei dati Modello dei dati Il modello è dato da una classe che implementa TableModel (o meglio, estende AbstractTableModel) Il contenuto di ogni cella è il prodotto dell’indice di riga per l’indice di colonna. Siccome gli indici partono da 0, dovremo incrementarli entrambi. Il modello definisce anche l’intestazione delle colonne Vista dei dati La tabella che mostra i dati è una istanza di JTable, che viene inizializzata con una istanza della classe precedente. Cabri, Denti, Zambonelli - GRAFICA in JAVA - 70 ESEMPIO 20: IL MODELLO DI DATI import javax.swing.table.AbstractTableModel; public class MyTableModel extends AbstractTableModel { // ritorna il numero di colonne public int getColumnCount() { return 10; } // ritorna il numero di righe public int getRowCount() { return 10;} // ritorna il contenuto di una cella public Object getValueAt(int row, int col) { // ritorna il prodotto return new Integer((row+1)*(col+1)); } // ritorna il nome della colonna public String getColumnName(int col) { // e' il numero di colonna return Integer.toString(col+1); } // specifica se le celle sono editabili public boolean isCellEditable(int row, int col) { // nessuna cella editabile return false; } } Cabri, Denti, Zambonelli - GRAFICA in JAVA - 71 ESEMPIO 20: LA TABELLA import javax.swing.*; public class Es20Panel extends JPanel { public Es20Panel() { // crea il modello di dati TableModel dataModel = new MyTableModel(); // crea la tabella JTable t = new JTable(dataModel); // aggiunge la tabella ad uno ScollPane JScrollPane scrollpane = new JScrollPane(t); // aggiunge lo ScrollPane al pannello add(scrollpane); } } Il pannello viene poi inserito in un JFrame come al solito Cabri, Denti, Zambonelli - GRAFICA in JAVA - 72 EVENTI DI TABELLA Naturalmente, ogni azione dell’utente sulla tabella genera un evento che può essere ascoltato da un ascoltatore La classe JTable stessa implementa diversi ascoltatori • • • • CellEditorListener TableModelListener ListSelectionListener TableColumnModelListener Non è sempre necessario implementare i metodi degli ascoltatori, perché la tabella rimane una vista dei dati contenuti nel modello: il programma fa quindi riferimento a quest’ultimo Si veda la documentazione Java per un approfondimento È invece importante riportare nel modello le modifiche fatte dall’utente ai valori nella tabella, come spiegato nell’esempio seguente Cabri, Denti, Zambonelli - GRAFICA in JAVA - 73 ESEMPIO 21: UNA LISTA DI LIBRI Vogliamo visualizzare una lista di libri, ognuno con titolo, autore, quantità, prezzo e valore totale, dato dal prezzo moltiplicato per la quantità Diamo la possibilità all’utente di modificare quantità e prezzo Ogni libro è rappresentato da una istanza della classe Book public class Book { public String title; // titolo public String author; // autore public int quantity; // quantita' public float price; // prezzo // costruttore public Book(String title, String quantity, float price) { this.title = title; this.author = author; this.quantity = quantity; this.price = price; } } Cabri, Denti, Zambonelli - GRAFICA in JAVA - 74 author, int ESEMPIO 21: IL MODELLO DI DATI import java.util.Vector; import javax.swing.table.AbstractTableModel; public class VectorTableModel AbstractTableModel { Vector v = null; // intestazioni delle colonne String[] ColName = {"Titolo", "Quantità", "Prezzo", "Valore" }; extends "Autore", public VectorTableModel(Vector v) { this.v = v; // inizializzato con il vettore } /** il numero di colonne */ public int getColumnCount() { return ColName.length; } /** numero righe = dimensione del vettore */ public int getRowCount() { return v.size(); } /** ritorna il contenuto di una cella */ public Object getValueAt(int row, int col) { // seleziona il libro Book b = (Book)v.elementAt(row); // la stringa corrispondente alla colonna switch (col){ case 0: return b.title; case 1: return b.author; case 2: return b.quantity; case 3: return b.price; case 4: return b.price * b.quantity; default: return ""; } } Cabri, Denti, Zambonelli - GRAFICA in JAVA - 75 ESEMPIO 21: IL MODELLO DI DATI - segue /** ritorna il nome della colonna */ public String getColumnName(int col) { return ColName[col]; } /** ritorna il tipo dei valori * serve per allineare correttamente i numeri */ public Class getColumnClass(int col) { return getValueAt(0, col).getClass(); } A differenza dell’esempio precedente, dobbiamo dire alla tabella che le colonne di quantità e prezzo sono editabili: il metodo isCellEditable() ritornerà quindi un valore diverso a seconda del numero di colonna. /** specifica se le celle sono editabili */ public boolean isCellEditable(int row, int col) { if ((col == 2) || (col == 3)) // solo la quantita' e il prezzo // sono modificabili return true; else // nessuna altra cella editabile return false; } Cabri, Denti, Zambonelli - GRAFICA in JAVA - 76 ESEMPIO21: IL MODELLO DI DATI - segue Per modificare i valori del modello a fronte di una modifica dell’utente sulla vista, è necessario implementare il metodo setValueAt(), che viene invocato dalla tabella ogni volta che l’utente modifica un valore in una cella Conoscendo la riga della cella modificata, possiamo recuperare il libro interessato; conoscendo la colonna, possiamo sapere quale attributo è stato modificato Dopodiché informiamo la tabella delle modifiche inviando un evento tramite il metodo fireTableDataChanged() /** metodo per gestire le modifiche dell'utente */ public void setValueAt(Object value, int row, int col) { Book b = (Book)v.elementAt(row); if (col == 2) // modifica la quantita' b.quantity = ((Integer)value).intValue(); if (col == 3) // modifica il prezzo b.price = ((Float)value).floatValue(); // notifica il cambiamento fireTableDataChanged(); } } si noti che va aggiornata la vista non solo della cella modificata dall’utente, ma anche del campo “Valore” che viene calcolato in base a quantità e prezzo Cabri, Denti, Zambonelli - GRAFICA in JAVA - 77 ESEMPIO 21: LA TABELLA import java.util.Vector; import javax.swing.*; import javax.swing.table.TableModel; public class PannelloTabellaVettore extends JPanel { public PannelloTabellaVettore () { // predispone il vettore Vector v = new Vector(3); Book b1 = new Book("Le avventure di Pinocchio", "Collodi", 40, 14.50F); Book b2 = new Book("La fattoria degli animali", "Orwell", 20, 12.90F); Book b3 = new Book("Signor Malaussene", "Pennac", 15, 9.00F); v.add(b1); v.add(b2); v.add(b3); // crea il modello di dati dal vettore TableModel dataModel = new VectorTableModel(v); // crea la tabella JTable t = new JTable(dataModel); // imposta la dimensione di visualizzazione t.setPreferredScrollableViewportSize( t.getPreferredSize()); // aggiunge la tabella ad uno ScollPane JScrollPane scrollpane = new JScrollPane(t); // aggiunge lo ScrollPane al pannello add(scrollpane); } } Il pannello viene poi inserito in un JFrame come al solito Cabri, Denti, Zambonelli - GRAFICA in JAVA - 78