Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 18
  1. #1

    JTable Refresh automatico

    Ciao a tutti!

    Mi sto cimentando nel cercare di refreshare in modo automatico la mia jtable ogni tot di tempo.

    Ci sono riuscito schedulando un timerTask creato passando l'istanza della mia DesktopApplicationView... per funzionare... funziona... tranne per il fatto che in qualche ciclo compare il seguente errore:

    Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException


    Questa è la mia TimerTask

    codice:
        class MyTask extends TimerTask {
    
        private DesktopApplication1View refrashframe;
    
        MyTask(DesktopApplication1View aThis) {
            //throw new UnsupportedOperationException("Not yet implemented");
            refrashframe = aThis;
    
        }
    
        @Override
        public void run() {
            System.out.println("Running the task");
            refrashframe.CaricaDati();
        }
    }

    Questo è quello che faccio nella classe DesktopApplication1View:

    codice:
          public DesktopApplication1View(SingleFrameApplication app) {
            super(app);
    
            initComponents();
            // Permetto di selezionare solo una riga alla volta della tabella
            jTable1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            // Riempio la tabella
            CaricaDati();
    
            java.util.Timer timer = new java.util.Timer();
            java.util.TimerTask task = new MyTask(this);
    
            // aspetta 10 secondi prima dell'esecuzione
            //timer.schedule(task, 1000);
    
            // aspetta 5 secondi prima dell'esecuzione,poi viene eseguita ogni 10 secondi
            timer.schedule(task, 5000, 5000);
            ...
         }
    
         public void CaricaDati() {
            mainPanel.setCursor(new Cursor(Cursor.WAIT_CURSOR));
            try {
                try {
                    // salvo la posizione della riga selezionata
                    int app = jTable1.getSelectedRow();
    
                    Connection con = desktopapplication1.DesktopApplication1.MyConection();
                    Statement st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
                    String query = "SELECT ID_IMPIANTO, NOME_IMPIANTO, RAG_SOC, DES_MARCA, DES_MODELLO, LAST_UPDATE, MAX_ERROR_LEVEL, COUNT_ERROR, FLG_EVASO FROM MIT.WHD_ALLARMI_IMPIANTI";
                    ResultSet rs = st.executeQuery(query);
                    GenericTableModel model = new GenericTableModel();
                    model.parseResultSet(rs);
                    jTable1.setModel(model);
                    jTable1.updateUI();
                    // reimposto la posizione della riga selezionata
                    if (app >= 0) {
                        jTable1.setRowSelectionInterval(app, app);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } finally {
                mainPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
        }
    Secondo voi posso utilizzare un altro metodo più corretto per fare il refresh automatico?
    L'errore a cosa può essere dovuto?

    Grazie... per la pazienza

    Alessio.

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Qui ci sono alcune questioni da affrontare.

    Innanzitutto hai usato un java.util.Timer e fin qui nulla di strano. Il Timer però esegue il task nel contesto del "suo" thread (quello di gestione del timer). Non nel contesto del EDT (event dispatch thread), quello della interfaccia utente.

    La regola basilare in Swing è che salvo casi particolari/documentati, l'accesso a qualunque componente della interfaccia utente va fatto solo nel contesto del EDT.
    Mentre tu nel contesto del thread del timer (non il EDT) ad un certo punto invochi jTable1.setModel(model);

    Questo è sbagliato. Come ho detto, qualunque accesso (salvo casi particolari) va fatto dal EDT. E non solo il setModel ... vedo che fai altre operazioni sulla interfaccia grafica.
    Per farla breve, devi fare queste operazioni nel contesto del EDT. Quindi devi usare il "solito" invokeLater() di SwingUtilities.

    E nota anche una cosa: updateUI() non ti serve ... è fatto per altro (ha a che fare con i Look and Feel), non devi usarlo.

    Inizia quindi a correggere la questione sull'accesso ai componenti, che sia nel EDT.

    Il fatto che cambi totalmente il model, istanziando un nuovo model, può anche non essere la cosa migliore del mondo .... L'alternativa ovviamente è aggiornare la struttura interna al model. Ma bisognerebbe vedere cosa è e come è fatto quel GenericTableModel.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Grazie per la risposta!
    Ma adesso vediamo se ho capito:

    Ho eliminato TimerTask e aggiunto un Runnable, ecco il codice:

    codice:
    public class DesktopApplication1View extends FrameView {
    
        final Runnable doCaricaDati = new Runnable() {
    
            @Override
            public void run() {
                System.out.println("run doCaricaDati");
                CaricaDati();
            }
        };
    
        public DesktopApplication1View(SingleFrameApplication app) {
            super(app);
            initComponents();
            // Permetto di selezionare solo una riga alla volta della tabella
            jTable1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);      
            SwingUtilities.invokeLater(doCaricaDati);
            ecc...
    A runtime funziona! ma giustamente, solo una volta, all'avvio dell'applicazione... come faccio a "schedulare" l'esecuzione di doCaricaDati ogni tot di secondi?

    Grazie ancora.

    Alessio.

    p.s. Sul cambiare totalmente il model della Jtable, mi sto rendendo conto anch'io che non va proprio bene... la domanda sui model sarà la prossimo domanda che metterò sul forum

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da io.alessio
    Ho eliminato TimerTask e aggiunto un Runnable, ecco il codice:

    A runtime funziona! ma giustamente, solo una volta, all'avvio dell'applicazione... come faccio a "schedulare" l'esecuzione di doCaricaDati ogni tot di secondi?
    Con java.util.Timer e TimerTask!! Io non ti ho detto di eliminarli!!!

    Io ho detto che non devi fare quei setXXX nel contesto del thread del timer ma nel contesto del EDT. E per fare questo si usa un piccolo Runnable da dare in pasto a invokeLater().
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    Mi sento molto tonto:>

    Quindi se rimetto il Timer e al timerTask gli passo il mio runnable dovrebbe essere corretto... Dimmi di Siii
    ... anche perchè così funziona!! e non mi da neanche più l'errore(Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException)!

    codice:
    class MyTask extends TimerTask {
    
        private Runnable refrashframe;
    
        MyTask(Runnable aThis) {
            refrashframe = aThis;
        }
    
        @Override
        public void run() {
            System.out.println("Running the task");
            SwingUtilities.invokeLater(refrashframe);
        }
    }
    
    public class DesktopApplication1View extends FrameView {
    
        final Runnable doCaricaDati = new Runnable() {
    
            @Override
            public void run() {
                System.out.println("run doCaricaDati");
                CaricaDati();
            }
        };    
    
        public DesktopApplication1View(SingleFrameApplication app) {
            super(app);
            initComponents();
            // Permetto di selezionare solo una riga alla volta della tabella
            jTable1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);                
            java.util.Timer timer = new java.util.Timer();
            java.util.TimerTask task = new MyTask(doCaricaDati);        
            timer.schedule(task, 0, 5000);
            ecc...

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da io.alessio
    Quindi se rimetto il Timer e al timerTask gli passo il mio runnable dovrebbe essere corretto... Dimmi di Siii
    No.

    Originariamente inviato da io.alessio
    ... anche perchè così funziona!! e non mi da neanche più l'errore(Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException)!
    Questi problemi sono "subdoli" perché non sono "sistematici" ma dipendono da temporizzazioni "sfortunate" tra i vari thread, proprio perché non c'è una apposita sincronizzazione e da un thread si fa qualcosa sullo stato di un oggetto che è usato anche da un altro thread (il EDT in questo caso).

    Ripeto che la cosa è molto semplice: quando vuoi far eseguire qualcosa nel contesto del EDT mentre sei nel contesto di un altro thread, crea un Runnable e passalo a invokeLater().
    In genere il corpo del run() dovrebbe essere tenuto abbastanza breve e quindi in questi casi è sufficiente anche solo una breve anonymous inner-class.

    codice:
    ....
    final GenericTableModel model = new GenericTableModel();
    model.parseResultSet(rs);
    
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            jTable1.setModel(model);
        }
    });
    .....
    E nota il final per model. Deve essere final per essere usabile nel run().
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    Sai che non ho ancora capito precisamente dove sto sbagliando!

    Sicuramente perchè mi mancano proprio le basi... ma se il mio codice è questo:

    codice:
    class MyTask extends TimerTask {
        private Runnable refrashframe;
    
        MyTask(Runnable aThis) {
            refrashframe = aThis;
    
        }
    
        @Override
        public void run() {
            System.out.println("Running the task");
            SwingUtilities.invokeLater(refrashframe);
        }
    }
    
    public class DesktopApplication1View extends FrameView {
    
        final Runnable doCaricaDati = new Runnable() {
    
            @Override
            public void run() {
                System.out.println("run doCaricaDati");
                CaricaDati();
            }
        };
    
        public DesktopApplication1View(SingleFrameApplication app) {
            super(app);
            initComponents();
            java.util.Timer timer = new java.util.Timer();
            java.util.TimerTask task = new MyTask(doCaricaDati);
            timer.schedule(task, 0, 500); 
            ecc...
        }
    
        public void CaricaDati() {
            mainPanel.setCursor(new Cursor(Cursor.WAIT_CURSOR));
            try {
                try {
                    Connection con = desktopapplication1.DesktopApplication1.MyConection();
                    Statement st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
                    String query = "SELECT ID_IMPIANTO, NOME_IMPIANTO, RAG_SOC, DES_MARCA, DES_MODELLO, LAST_UPDATE, MAX_ERROR_LEVEL, COUNT_ERROR, FLG_EVASO FROM MIT.WHD_ALLARMI_IMPIANTI";
                    ResultSet rs = st.executeQuery(query);
                    final GenericTableModel model = new GenericTableModel();
                    model.parseResultSet(rs);
    
                    SwingUtilities.invokeLater(new Runnable() {
    
                        public void run() {
                            int app = jTable1.getSelectedRow();
                            jTable1.setModel(model);
                            if (app >= 0) {
                                jTable1.setRowSelectionInterval(app, app);
                            }
                        }
                    });
    
                    /*GenericTableModel model = new GenericTableModel();
                    model.parseResultSet(rs);
                    jTable1.setModel(model);*/               
    
                    st.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } finally {
                mainPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
            }
        }
    Sono veramente in difficoltà nel capire cosa non va... anche se però anch'io immagino che una cosa che si sa risulta sempre molto semplice

    Ti ho postato quello che secondo me è il core del problema, se mi evidenzi dove sbaglio in rosso... te ne sarei molto grato!

  8. #8
    Utente di HTML.it
    Registrato dal
    Feb 2009
    Messaggi
    502
    Se ho capito bene i thread di swing e l'uso di invokelater...
    ... nel thread dove credo la GUI, se ho delle operazioni lunghe da fare, o anche non lunghe, le inserisco in uun Runnable, richiamato da invokelater?
    Oppure le metto in una classe opportunamente costruita? Così da non tenere occupato troppo il thread principale dell'EDT?
    Oppure non c'ho capito un cavolo?

  9. #9
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Rubox
    ... nel thread dove credo la GUI, se ho delle operazioni lunghe da fare, o anche non lunghe, le inserisco in uun Runnable, richiamato da invokelater?
    No!! Lo dico ancora una volta: invokeLater() serve per richiedere di far eseguire "qualcosa" (il run() di un Runnable) nel contesto del EDT. Il EDT è il thread che si occupa principalmente di tutto il disegno della interfaccia utente e del dispacciamento degli eventi. E non va mai tenuto impegnato con del "tuo" codice per troppo tempo pena ... "congelamento" di tutta la interfaccia!

    Originariamente inviato da Rubox
    Oppure le metto in una classe opportunamente costruita? Così da non tenere occupato troppo il thread principale dell'EDT?
    Non centra tanto "la classe" in sé ... centra il "flusso" di esecuzione. Se devi fare operazioni "lunghe" devi farle in un thread di esecuzione separato e questo generalmente consiste nell'avere un java.lang.Thread e farlo partire (start()). Puoi:
    1) Estendere Thread e fare il tuo "lavoro" nel run()
    oppure
    2) Implementare la interfaccia Runnable (in una qualunque tua classe) e fare il tuo "lavoro" nel run(). Il Runnable lo passi al costruttore di Thread
    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
    Registrato dal
    Feb 2009
    Messaggi
    502
    Ok, non ho capito un cavolo e ancora non capisco, malgrado aver letto sul sito della Sun gli articoli sui thread .

    Faccio un piccolo esempio così giusto per capire.
    Creo un'interfaccia con a sinistra un albero costruito a partire da dati in un DB.
    Ad ogni nodo, selezionandolo, mi compare al centro della GUI un pannello che mi presenta i dati memorizzati in una struttura.
    In questo esempio, per non bloccare la GUI, dove dovrei usare invokelater?
    Lo so, sono de coccio, ma non l'ho capito

    codice:
    // classe di esempio
    public class EsempioGUI{
    
      public EsempioGui(){
        // creo tutti i controlli grafici
        creaInterfacciaGUI();
        // leggo dal DB
        leggiDatabase();
        ...
      }
    
      private void valueChanged(TreeSelectionEvent e) {
        // quando cambio il DB allora aggiorno l'albero
        aggiornaAlbero();
      }
    }

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.