Le composant JTable permet de créer des tableaux. On l'utilise en relation avec une classe dérivée de AbstractTableModel qui permet de décrire le contenu du tableau (nombre de lignes et de colonnes, contenu des cellules).
Nous allons écrire une application qui affichera dans un tableau le contenu d'un fichier de données au format texte utilisant la virgule comme séparateur. La première ligne du fichier donnera les titres des colonnes du tableau.
Cette classe dérivée de la classe AbstractTableModel devra implémenter un certain nombre de méthodes déclarées abstraites. Elle utilisera pour ce faire les données contenues dans un fichier.
Nous utiliserons trois variables:
On obtient le code suivant:
import javax.swing.*; import javax.swing.table.*; import java.io.*; import java.util.*; public class DataFileTableModel extends AbstractTableModel { protected Vector data; //données protected Vector columnNames ; //noms de colonnes protected String datafile; //nom du fichier de données
Le constructeur récupère le nom du fichier de données puis initialise les deux champs de type Vector en lisant le fichier dans la méthode initVectors.
public DataFileTableModel(String f) { datafile=f; initVectors(); } public void initVectors() { String ligne; data=new Vector(); columnNames=new Vector(); try { FileInputStream fin=new FileInputStream(datafile); BufferedReader br=new BufferedReader( new InputStreamReader(fin)); // lecture des noms de colonnes (1ère ligne) ligne=br.readLine(); StringTokenizer st1=new StringTokenizer(ligne, ","); while(st1.hasMoreTokens()) columnNames.addElement(st1.nextToken()); // lecture des données while ((ligne = br.readLine()) != null) { StringTokenizer st2=new StringTokenizer(ligne, ","); while(st2.hasMoreTokens()) data.addElement(st2.nextToken()); } br.close(); } catch (Exception e) { e.printStackTrace(); } }
La première ligne du fichier permet de déterminer le nombre et les noms des colonnes, elle sert donc à initialiser le champ columnNames. Les lignes suivantes permettent d'initialiser le champ data.
Il nous reste à implémenter les méthodes qui permettront de construire et d'afficher le tableau.
Le nombre de colonnes est le nombre d'éléments du champ columnNmes.
public int getColumnCount() { return columnNames.size(); }
Le nombre de lignes est obtenu en divisant le nombre d'éléments du champ data par le nombre de colonnes.
public int getRowCount() { return data.size()/getColumnCount(); }
Les noms des colonnes sont contenus dans le champ columnNames.
public String getColumnName(int columnIndex) { String colName=""; if (columnIndex<=getColumnCount()) colName=(String)columnNames.elementAt(columnIndex); return colName; }
Dans notre exemple, toutes les données sont des chaînes de caractères, donc de classe String.
public Class getColumnClass(int columnIndex){ return String.class; }
On indique ici quelles cellules sont modifiables. Dans notre exemple, aucune cellule ne le sera.
public boolean isCellEditable(int rowIndex, int columnIndex) { return false; }
On donne ici le contenu de chaque cellule sous forme d'objet. Dans notre exemple, ce contenu est une chaîne de caractères contenue dans le champ data. Il faut tenir compte du fait que les données sont placées les unes derrière les autres et donc recalculer leur position en fonction de la ligne et de la colonne de la cellule.
public Object getValueAt(int rowIndex, int columnIndex) { return (String)data.elementAt( (rowIndex*getColumnCount())+columnIndex); }
On indique ici comment prendre en compte les modifications du contenu des cellules effectuées par l'utilisateur. Dans notre exemple, aucune cellule n'est éditable, il n'y a donc rien à faire.
public void setValueAt(Object aValue, int rowIndex, int columnIndex) { }
Nous allons construire un JPanel qui contiendra un élément JTable associé au DataFileTableModel créé précédemment.
Il nous suffira ensuite d'écrire une méthode main qui créera une fenêtre contenant le JPanel créé.
On importe les packages nécessaires et on fait dériver la classe DataFileTable de la classe JPanel.
import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.io.*; import java.util.*; public class DataFileTable extends JPanel { }
On récupère le nom du fichier de données (qui sera déterminé dans la méthode main), puis on crée le modèle de table et la table. La table est placée dans un JScrollPane pour obtenir des ascenceurs lorsque c'est nécessaire.
public DataFileTable(String dataFilePath) { JTable table; // le tableau DataFileTableModel model; // le modèle //fonte Font f=new Font("SanSerif",Font.PLAIN,24); setFont(f); //gestionnaire de positionnement setLayout(new BorderLayout()); //construction du modèle de remplissage à partir du fichier model = new DataFileTableModel(dataFilePath); //création du tableau table=new JTable(); table.setModel(model); table.createDefaultColumnsFromModel(); //scroller JScrollPane scrollpane=new JScrollPane(table); add(scrollpane); }
La méthode getPreferredSize() permet de fixer les dimensions préférées du tableau.
public Dimension getPreferredSize() { return new Dimension(400, 300); }
La méthode principale permet de récupérer un nom de fichier en paramètre, puis de créer un tableau de type DataFileTable et de l'insérer dans une fenêtre.
public static void main(String args[]) { //la fenêtre du programme JFrame fen=new JFrame("Table"); //le tableau DataFileTable tablo; String nomFichier="datas.txt"; if (args.length>0) nomFichier=args[0]; tablo=new DataFileTable(nomFichier); //configuration de la fenêtre fen.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); fen.setForeground(Color.black); fen.setBackground(Color.lightGray); fen.getContentPane().add(tablo,"Center"); fen.setSize(tablo.getPreferredSize()); //affichage fen.setVisible(true); //écouteur pour fermeture fen.addWindowListener(new WindowCloser()); }
Il reste à créer la classe WindowCloser chargée de la gestion des évènements liés à la fenêtre.
class WindowCloser extends WindowAdapter { public void windowClosing(WindowEvent e) { Window win=e.getWindow(); //effacer la fenêtre win.setVisible(false); //terminer le programme System.exit(0); } }