Pagina 1 di 3 1 2 3 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 27
  1. #1
    Utente di HTML.it L'avatar di Cool81
    Registrato dal
    Dec 2008
    Messaggi
    160

    Jtable e AbstractTableModel

    Devo creare una jTable.

    Come la jList, anche per riempire la jTable, dobbiamo ricorrere ad un modello, ad es. AbstractTableModel.

    Quindi ci costruiamo la classe che estende AbstractTableModel.


    codice:
    public class SimpleTableModel extends DefaultTableModel {
        public SimpleTableModel(Object[][] data, Object[] columnNames) {
           ...
        }
    
       //e gli altri metodi astratti...

    L'oggetto columnNames glielo posso passare staticamente, magari istanziandolo prima.
    Ho difficoltà nel primo parametro.

    Nel mio caso la tabella nella prima colonna avrà dei nomi e nella secondo i numeri di telefono, presi da un ArrayList<String>.

    Come si scrive questo codice??????



  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Credo sia il caso di fare un esempio completo di implementazione di un table model, visto che non mi sembra di averne mai postato uno ... almeno non così completo.

    codice:
    import java.awt.*;
    import java.awt.event.*;
    import java.util.*;
    import javax.swing.*;
    import javax.swing.table.*;
    
    public class ElencoPersoneFrame extends JFrame {
        private PersonaTableModel tableModel;
        private JTable table;
        private JScrollPane scrollPane;
        private JButton aggiungiButton;
    
        public ElencoPersoneFrame() {
            super ("Elenco Persone");
    
            setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
            setSize(450, 350);
    
            ArrayList<Persona> listaPersone = new ArrayList<Persona>();
    
            listaPersone.add(new Persona("Mario", "Rossi", 1972, false));
            listaPersone.add(new Persona("Giacomo", "Bianchi", 1946, false));
            listaPersone.add(new Persona("Roberto", "Verdi", 1985, true));
    
            tableModel = new PersonaTableModel(listaPersone);
    
            table = new JTable(tableModel);
            scrollPane = new JScrollPane(table);
    
            aggiungiButton = new JButton("Aggiungi");
    
            aggiungiButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    // Crea una persona predefinita ... giusto per esempio
                    // L'ideale sarebbe presentare una dialog per l'input di una persona
                    Persona p = new Persona("Gianni", "Neri", 1983, false);
    
                    // Modifica direttamente il table model
                    tableModel.aggiungiPersona(p);
                }
            });
    
            getContentPane().add(scrollPane, BorderLayout.CENTER);
            getContentPane().add(aggiungiButton, BorderLayout.SOUTH);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    ElencoPersoneFrame f = new ElencoPersoneFrame();
                    f.setVisible(true);
                }
            });
        }
    }
    
    
    class Persona {
        private String nome;
        private String cognome;
        private int annoNascita;
        private boolean disoccupato;
    
        public Persona(String nome, String cognome, int annoNascita, boolean disoccupato) {
            this.nome = nome;
            this.cognome = cognome;
            this.annoNascita = annoNascita;
            this.disoccupato = disoccupato;
        }
    
        public String getNome() { return nome; }
        public String getCognome() { return cognome; }
        public int getAnnoNascita() { return annoNascita; }
        public boolean isDisoccupato() { return disoccupato; }
    
        public void setNome(String nome) { this.nome = nome; }
        public void setCognome(String cognome) { this.cognome = cognome; }
        public void setAnnoNascita(int annoNascita) { this.annoNascita = annoNascita; }
        public void setDisoccupato(boolean disoccupato) { this.disoccupato = disoccupato; }
    }
    
    
    class PersonaTableModel extends AbstractTableModel {
        private ArrayList<Persona> listaPersone;
    
        public PersonaTableModel(ArrayList<Persona> listaPersone) {
            this.listaPersone = listaPersone;
        }
    
        public int getRowCount() {
            return listaPersone.size();
        }
    
        public int getColumnCount() {
            return 4;
        }
    
        public String getColumnName(int column) {
            switch (column) {
                case 0: return "Nome";
                case 1: return "Cognome";
                case 2: return "Anno nascita";
                case 3: return "Disoccupato?";
            }
    
            return "";
        }
    
        public Class getColumnClass(int column) {
            switch (column) {
                case 0: return String.class;
                case 1: return String.class;
                case 2: return Number.class;    // il renderer/editor di default per Number allinea a destra
                case 3: return Boolean.class;   // il renderer/editor di default per Boolean mostra un "checkbox"
            }
    
            return Object.class;
        }
    
        public boolean isCellEditable(int row, int column) {
            return column == 3;   // solo la colonna 3 è editabile!
        }
    
        public Object getValueAt(int row, int column) {
            Persona p = listaPersone.get(row);
    
            switch (column) {
                case 0: return p.getNome();
                case 1: return p.getCognome();
                case 2: return p.getAnnoNascita();   // auto-boxing!
                case 3: return p.isDisoccupato();    // auto-boxing!
            }
    
            return null;
        }
    
        public void setValueAt(Object value, int row, int column) {
            Persona p = listaPersone.get(row);
    
            switch (column) {
                case 0: p.setNome((String) value); break;
                case 1: p.setCognome((String) value); break;
                case 2: p.setAnnoNascita((Integer) value); break;   // unboxing!
                case 3: p.setDisoccupato((Boolean) value); break;   // unboxing!
            }
        }
    
    
        // Metodo "custom", non inerente a TableModel/AbstractTableModel
        public void aggiungiPersona(Persona p) {
            listaPersone.add(p);
    
            int row = listaPersone.size() - 1;
    
            // IMPORTANTE, notifica l'aggiunta di una riga nel model
            fireTableRowsInserted(row, row);
        }
    }
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Utente di HTML.it L'avatar di Cool81
    Registrato dal
    Dec 2008
    Messaggi
    160
    Ok. Ho implementato il mio TableModel:

    codice:
    class SimpleTableModel extends AbstractTableModel{
          //Intestazione delle colonne
          String[] columnNames = {"Nome", "Telefono"};
          private ArrayList<Contact> contatti;
    
            public SimpleTableModel(ArrayList<Contact> contatti) {
                this.contatti = contatti;
            }
    
            //Numero di righe uguale alla dimensione dell'ArrayList
            public int getRowCount() {
                return contatti.size();
            }
    
            //Numero di colonne
            public int getColumnCount() {
                return columnNames.length;
            }
    
            //Ritorno il contenuto di una cella
            public Object getValueAt(int rowIndex, int columnIndex) {
                //Seleziona il contatto
                Contact c = (Contact)contatti.get(rowIndex);
                String val = null;
                switch (columnIndex){
                    case 0: val = c.getName();
                    case 1: val = c.getTel();
                    break;
                    default: val = "";
                }
                return val;
            }
    
            // ritorna il nome della colonna
            @Override
            public String getColumnName(int col) {
                return columnNames[col];
            }
    }
    Ora provo ad associare questo tableModel ad una jtable.
    E poi devo implementare i metodi di ricerca che aggiornano subito la jtable.

    Se qualcuno gli dà un'occhiata mi può dire se ci sono errori evidenti?

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Cool81
    Se qualcuno gli dà un'occhiata mi può dire se ci sono errori evidenti?
    Nel getValueAt il cast a Contact è superfluo (usi i generics) e nello switch hai messo il break solo per il case 1, il case 0 "fluisce" anche dentro il case 1 e ovviamente non lo vorresti.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Utente di HTML.it L'avatar di Cool81
    Registrato dal
    Dec 2008
    Messaggi
    160
    Pensavo di avere inviato la risposta, ma nn risulta dal forum..allora riscrivo...

    Grazie della correzione degli errori, infatti ora ho modificato così il metodo in questione:

    codice:
    public Object getValueAt(int row, int col) {
    
               //Seleziona il contatto
                Contact c = contatti.get(row);
                switch (col){
                    case 0: return c.getName();
                    case 1: return c.getTel();
                }
                return null;
            }

    Adesso devo:

    1. aggiungere un'icona (uguale per tutti) per ogni contatto
    2. fare un metodo di ricerca ke aggiorni subito la tableModel

    Per il primo problema ho provato ad aggiungere una colonna alla tabella per metterci dentro l'icona:

    codice:
    public Object getValueAt(int row, int col) {
    
               ImageIcon icon = new ImageIcon(getClass().getResource("/images/smile.png"));
    
                //Seleziona il contatto
                Contact c = contatti.get(row);
                switch (col){
                    case 0: return icon;
                    case 1: return c.getName();
                    case 2: return c.getTel();
                }
                return null;
            }
    Ma facendo così mi stampa il percorso dell'icona invece dell'icona...esiste un modo più appropriato per fare questa cosa?

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Cool81
    1. aggiungere un'icona (uguale per tutti) per ogni contatto
    Se definisci una colonna in cui come Class fai ritornare Icon.class (o ImageIcon.class) e come oggetto fai ritornare sempre un certo ImageIcon, hai raggiunto il tuo obiettivo.

    Originariamente inviato da Cool81
    2. fare un metodo di ricerca ke aggiorni subito la tableModel
    Hai sicuramente già capito come funziona (avendolo già visto per JList) .... devi modificare il model e quindi fare un fireXXX per notificare la/e modifiche.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Utente di HTML.it L'avatar di Cool81
    Registrato dal
    Dec 2008
    Messaggi
    160
    Sì, penso di aver capito come funziona....e ho implementato così la classe del tableModel che ha un metodo di ricerca:

    codice:
      class SimpleTableModel extends AbstractTableModel{
          //Intestazione delle colonne
          String[] columnNames = {"Nome", "Telefono"};
          private ArrayList<Contact> contatti;
          private ArrayList<Contact> resultContatti;
    
            public SimpleTableModel(ArrayList<Contact> contatti) {
                this.contatti = contatti;
                resultContatti = new ArrayList<Contact>();
                search2("");  // search fittizio per setup iniziale
            }
    
            //Numero di righe uguale alla dimensione dell'ArrayList
            public int getRowCount() {
                return contatti.size();
            }
    
            //Numero di colonne
            public int getColumnCount() {
                return columnNames.length;
            }
    
            //Ritorno il contenuto di una cella
            public Object getValueAt(int row, int col) {
               //Seleziona il contatto
                Contact c = contatti.get(row);
                switch (col){
                    case 0: return c.getName();
                    case 1: return c.getTel();
                }
                return null;
            }
    
            // ritorna il nome della colonna
            @Override
            public String getColumnName(int col) {
                return columnNames[col];
            }
    
            // Metodo custom per eseguire la ricerca
            public void search2(String searchString) {
                resultContatti.clear();
                if(searchString.equals("")){
                    for(int i = 0; i < contatti.size() ; i++){
                        resultContatti.add(contatti.get(i));
                    }
                    fireTableDataChanged();
                }
                else{
                    for (int i = 0; i < contatti.size(); i++) {
                        if (contatti.get(i).getName().toLowerCase().contains(searchString.toLowerCase())) {
                                resultContatti.add(contatti.get(i));
                        }
                       fireTableDataChanged();
                    }
                }
            }
    
    }
    E ho gestito gli eventi sulla textfield dove viene inserita la parola o le lettere da cercare.
    Gli eventi sono ascoltati...ma la tableModel non viene aggiornata...forse sbaglio il fireTableDataChanged()?

  8. #8
    Utente di HTML.it L'avatar di Cool81
    Registrato dal
    Dec 2008
    Messaggi
    160
    Ho letto qualcosa...ma non ci ho capito molto pechè come al solito su internet si trova tutto o niente.
    Non ho capito se devo aggiungere un evento alla tableModel e passando con il metodo

    codice:
    fireTableChanged(evento);
    Ma che evento ci devo mettere?

  9. #9
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Cool81
    Ho letto qualcosa...ma non ci ho capito molto pechè come al solito su internet si trova tutto o niente.
    Non ho capito se devo aggiungere un evento alla tableModel e passando con il metodo

    fireTableChanged(evento);
    Più che altro ci vorrebbe un po' di "intuizione" .... Vengono registrati dei listener sul table model e l'oggetto evento passato ai listener è un TableModelEvent.

    TableModelEvent può indicare molti tipi di modifiche .... tutte quelle possibili/utili.

    Se usi fireTableChanged(TableModelEvent e) sì, sei tu che devi istanziare l'evento ma altrimenti puoi usare gli altri fireXXX che "sintetizzano" l'evento a partire da informazioni più semplici es. solo il range di righe modificate.

    E nota un altro tuo errore: tu "esponi" i dati di contatti ... non di resultContatti!!! Ovvio che non "vedi" modifiche.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  10. #10
    Utente di HTML.it L'avatar di Cool81
    Registrato dal
    Dec 2008
    Messaggi
    160
    I fireXXX a disposizione per questo oggetto sono:

    1. fireTableStructureChanged()
    2. fireTableRowsInserted()
    3. fireTableRowsUpdated(int firstRow,int lastRow)
    4. fireTableRowsDeleted(int firstRow,int lastRow)
    5. fireTableCellUpdated(int firstRow,int lastRow)
    6. fireTableChanged(TableModelEvent e)
    7. fireTableDataChanged()

    Per 'intuizione' credo che 1,2 e 4 non facciano al mio caso.

    Il 7 fa questo:

    Notifies all listeners that all cell values in the table's rows may have changed. The number of rows may also have changed and the JTable should redraw the table from scratch. The structure of the table (as in the order of the columns) is assumed to be the same.
    Ma l'ho provato e non funziona.

    Ora ho provato il 3 che fa:
    Notifies all listeners that rows in the range [firstRow, lastRow], inclusive, have been updated.
    Quindi ho scritto così il metodo search:

    codice:
     // Metodo custom per eseguire la ricerca
            public void search2(String searchString) {
                resultContatti.clear();
                if(searchString.equals("")){
                    for(int i = 0; i < contatti.size() ; i++){
                        resultContatti.add(contatti.get(i));
                    }
    
                    fireTableRowsUpdated(0, resultContatti.size()-1);
    
                }
                else{
                    for (int i = 0; i < contatti.size(); i++) {
                        if (contatti.get(i).getName().toLowerCase().contains(searchString.toLowerCase())) {
                                resultContatti.add(contatti.get(i));
                        }
                        fireTableRowsUpdated(0, resultContatti.size()-1);
                    }  
                }
            }
    Ma non vedo nessun effetto sulla tabella, cioè non la vedo aggiornare mentre effettuo la ricerca.

    Ora provo gli altri..ma fin qua ho posso aver sbagliato qualcosa?

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.