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

    ExecutorService, JTable e JProgressBar

    ciao!

    sto cercando di capire meglio ExecutorService.
    quello che vorrei fare è una volta scelta la directory con un JFileChooser:
    - avviare la JProgressBar in modalità setIndeterminate
    - avviare la procedura di scan della directory che riempie il model della JTable
    - aggiungere le righe al model
    - lanciare un metodo che mi setta la larghezza delle colonne della JTable
    - finita la procedura stoppare la JProgressBar

    per ora ho fatto questo:
    codice:
    FileChooserOpen fco = new FileChooserOpen();
                    fco.showOpenDialog(null);
                    ExecutorService es = Executors.newSingleThreadExecutor();
                    es.submit(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                bar.setIndeterminate(true);
                                bar.setString("Loading...");
                                File dir = fco.getDir();
                                Scan utils = new Scan();
                                ArrayList<Record> list = utils.scanDir(dir.toPath());
                                for (int i = 0; i < list.size(); i++) {
                                    String n = list.get(i).getNome();
                                    String t = list.get(i).getTipo();
                                    String p = list.get(i).getPath();
                                    Object[] row = {n, t, p};
                                    model.addRow(row);
                                }
                                resizeColumnWidth();
                            } catch (IOException ex) {
                                JOptionPane.showMessageDialog(null, ex.getMessage());
                            }
                        }
                    });
                    es.shutdown();
                    bar.setIndeterminate(false);
                    bar.setString("");
    la JTable viene riempita correttamente, ma la JProgressBar non viene stoppata.
    inoltre ho questi errori:
    codice:
    Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at javax.swing.DefaultRowSorter.convertRowIndexToModel(DefaultRowSorter.java:518)
        at javax.swing.JTable.convertRowIndexToModel(JTable.java:2642)
        at javax.swing.JTable.getValueAt(JTable.java:2717)
        at javax.swing.JTable.prepareRenderer(JTable.java:5706)
        at javax.swing.plaf.synth.SynthTableUI.paintCell(SynthTableUI.java:683)
        at javax.swing.plaf.synth.SynthTableUI.paintCells(SynthTableUI.java:580)
        at javax.swing.plaf.synth.SynthTableUI.paint(SynthTableUI.java:364)
        at javax.swing.plaf.synth.SynthTableUI.update(SynthTableUI.java:275)
        at javax.swing.JComponent.paintComponent(JComponent.java:780)
        at javax.swing.JComponent.paint(JComponent.java:1056)
        at javax.swing.JComponent.paintToOffscreen(JComponent.java:5210)
        at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:290)
        at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
        at javax.swing.JComponent._paintImmediately(JComponent.java:5158)
        at javax.swing.JComponent.paintImmediately(JComponent.java:4969)
        at javax.swing.RepaintManager$4.run(RepaintManager.java:831)
        at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
        at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
        at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
        at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
        at java.awt.EventQueue.access$500(EventQueue.java:97)
        at java.awt.EventQueue$3.run(EventQueue.java:709)
        at java.awt.EventQueue$3.run(EventQueue.java:703)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
    dove sto sbagliando??

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da fermat Visualizza il messaggio
    dove sto sbagliando??
    Innanzitutto una questione importantissima. L'accesso ai componenti e in generale alla interfaccia utente va fatto solo ed esclusivamente nel contesto del Event Dispatch Thread (EDT). Salvo alcune operazioni che sono note per essere thread-safe (sono poche).

    In un thread che non è il EDT (non importa se creato direttamente con Thread, con l'Executor, tramite SwingWorker o altro) non puoi accedere alla UI. Quindi:

    bar.setIndeterminate(true) non lo puoi fare lì così direttamente in quel run()
    bar.setString("Loading...") nemmeno
    model.addRow(row) neanche (i model non sono thread-safe, almeno non in senso generale o per specifica)
    resizeColumnWidth() non so di preciso cosa fa ma se tocca il JTable, neanche questo
    JOptionPane.showMessageDialog(null, ex.getMessage()) idem
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    ciao andbin!


    ho provato a cambiare usando SwingWorker.
    questo pare funzionare:
    codice:
                    FileChooserOpen fco = new FileChooserOpen();
                    fco.showOpenDialog(null);
                    File dir = fco.getDir();
                    SwingWorker worker = new SwingWorker<Void, Void>() {
                        @Override
                        protected Void doInBackground() {
                            try {
                                north.getBtnStop().setEnabled(true);
                                bar.setIndeterminate(true);
                                bar.setString("Loading...");
                                Scan utils = new Scan();
                                ArrayList<Record> list = utils.scanDir(dir.toPath());
                                countFile = list.size();
                                for (int i = 0; i < list.size(); i++) {
                                    String n = list.get(i).getNome();
                                    String t = list.get(i).getTipo();
                                    String p = list.get(i).getPath();
                                    Object[] row = {n, t, p};
                                    model.addRow(row);
                                    try {
                                        Thread.sleep(200);
                                    } catch (InterruptedException ex) {
                                        JOptionPane.showMessageDialog(null, ex.getMessage());
                                    }
                                }
                            } catch (IOException ex) {
                                JOptionPane.showMessageDialog(null, ex.getMessage());
                            }
                            return null;
                        }
    
                        @Override
                        public void done() {
                            north.getLabelCount().setText("No. file " + countFile);
                            north.getBtnStop().setEnabled(false);
                            resizeColumnWidth();
                            bar.setIndeterminate(false);
                            bar.setString("");
                        }
                    };
                    worker.execute();
    ma a prescindere dal fatto che funzioni, può andare come soluzione?

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da fermat Visualizza il messaggio
    ho provato a cambiare usando SwingWorker.
    Il succo, purtroppo, NON cambia. doInBackground è eseguito in un thread che non è il EDT. Quindi:

    north.getBtnStop().setEnabled(true);
    bar.setIndeterminate(true);
    bar.setString("Loading...");
    model.addRow(row);
    JOptionPane.showMessageDialog(null, ex.getMessage());

    NON li dovresti fare lì così.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  5. #5
    ok, immaginavo.

    però a questo punto non ho ben capito.
    come si dovrebbe svolgere il tutto?
    seguendo il flusso a livello teorico:
    - clicco su un item menu e lancio il file chooser per scegliere la directory
    - scelta la directory devo:
    -- riempire una lista che riempie il model della jtable
    -- attivare un button che serve per stoppare l'operazione
    -- attivare la jprogressbar
    - finito lo scan (o cliccando sul button) dovrei:
    -- disattivare il button
    -- disattivare la progress bar
    -- avere la jtable bella pronta

    ora, ho capito che dovrei fare l'update della gui nell'EDT, ma non ho capito come.
    perchè se faccio balmante così:
    codice:
                    FileChooserOpen fco = new FileChooserOpen();
                    fco.showOpenDialog(null);
                    File dir = fco.getDir();
                    try {
                        north.getBtnStop().setEnabled(true);
                        bar.setIndeterminate(true);
                        bar.setString("Loading...");
                        Scan utils = new Scan();
                        ArrayList<Record> list = utils.scanDir(dir.toPath());
                        countFile = list.size();
                        for (int i = 0; i < list.size(); i++) {
                            String n = list.get(i).getNome();
                            String t = list.get(i).getTipo();
                            String p = list.get(i).getPath();
                            Object[] row = {n, t, p};
                            model.addRow(row);
    
                        }
                        north.getLabelCount().setText("No. file " + countFile);
                        north.getBtnStop().setEnabled(false);
                        resizeColumnWidth();
                        bar.setIndeterminate(false);
                        bar.setString("");
                    } catch (IOException ex) {
                        JOptionPane.showMessageDialog(null, ex.getMessage());
                    }
    - la lista viene riempita, e a fine operazione la jtable hai tutti i dati
    - ma l'attivazione / disattivazione del button / progressbar non avviene

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da fermat Visualizza il messaggio
    - la lista viene riempita, e a fine operazione la jtable hai tutti i dati
    - ma l'attivazione / disattivazione del button / progressbar non avviene
    Perché ora tutto il tuo codice di scansione del file-system lo stai eseguendo nel contesto del Event Dispatch Thread e quindi lo stai tenendo "impegnato" tu. E siccome c'è un solo thread per la UI (appunto il EDT), o fa una cosa o fa un'altra. Pertanto finché tieni impegnato tu il EDT, il framework non può dispacciare eventi né disegnare i componenti. La tua UI è completamente "congelata" e non responsiva.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  7. #7
    ok.
    se ho capito il ragionamento:
    - clicco su un item menu:
    -- attivo un button che serve per stoppare l'operazione
    -- attivo la jprogressbar
    -- lancio il file chooser per scegliere la directory
    - scelta la directory:
    -- nello SwingWorker lancio la scansione della directory, e riempio l'ArrayList
    - quando il worker ha finito:
    -- disattivo il button
    -- disattivo la progress bar
    -- riempio la jtable
    (poi gestirò anche il button di stop).

    se il filo logico è giusto, mi verrebbe da fare così:
    codice:
                    north.getBtnStop().setEnabled(true);
                    bar.setIndeterminate(true);
                    bar.setString("Loading...");
                    FileChooserOpen fco = new FileChooserOpen();
                    fco.showOpenDialog(null);
                    File dir = fco.getDir();
                    Scan utils = new Scan();
                    SwingWorker worker = new SwingWorker<Void, Void>() {
                        @Override
                        protected Void doInBackground() {
                            try {
                                list = utils.scanDir(dir.toPath());
                                countFile = list.size();
                            } catch (IOException ex) {
                                JOptionPane.showMessageDialog(null, ex.getMessage());
                            }
                            return null;
                        }
    
                        @Override
                        protected void done() {
                            System.out.println("OK");
                        }
                    };
                    worker.execute();
                    if (worker.isDone()) {
                        for (int i = 0; i < list.size(); i++) {
                            String n = list.get(i).getNome();
                            String t = list.get(i).getTipo();
                            String p = list.get(i).getPath();
                            Object[] row = {n, t, p};
                            model.addRow(row);
                        }
                        north.getLabelCount().setText("No. file " + countFile);
                        north.getBtnStop().setEnabled(false);
                        resizeColumnWidth();
                        bar.setIndeterminate(false);
                        bar.setString("");
                    }
    con il problema che l'OK viene stampato.
    ma non entra mail nell'if worker.isDone().

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da fermat Visualizza il messaggio
    con il problema che l'OK viene stampato.
    ma non entra mail nell'if worker.isDone().
    Il worker.execute() è praticamente immediato, ritorna subito. Quindi appena dopo isDone() ragionevolmente non può essere true!

    Mi spiace ma stai facendo troppi "giri" a vuoto. Prova a leggere bene la documentazione javadoc di SwingWorker e il tutorial https://docs.oracle.com/javase/tutor...cy/worker.html .
    Poi nel weekend, appena ho tempo, vedo di scrivere un bel esempio completo.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  9. #9
    si tu probabilmente hai ragione.

    ma il discorso è che se cerco in giro leggo tutti esempi in cui l'update della gui viene fatta nel done(), o nel process().
    cmq nello SwingWorker.

    tipo qui http://grepcode.com/file/repository....ingWorker.java
    oppure qui http://stackoverflow.com/questions/2...update-the-gui (in cui i dati al model vengono aggiunti nel process()).

    ma da quello che ho interpretato dai tuoi consigli, non dovrei fare così!
    cmq provo a leggere meglio la documentazione e gli altri esempi.
    sicuramente mi sarà sfuggito qualcosa.

    intanto grazie!

  10. #10
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Quote Originariamente inviata da fermat Visualizza il messaggio
    ma il discorso è che se cerco in giro leggo tutti esempi in cui l'update della gui viene fatta nel done(), o nel process().
    Appunto. process e done li puoi ridefinire tu e vengono invocati non da te direttamente ma dal SwingWorker nel contesto del EDT.
    done viene chiamato dopo che doInBackground è terminato. process invece viene invocato quando viene "pubblicato" qualcosa con il publish eseguito da dentro il doInBackground.

    Se hai afferrato, vedi che SwingWorker aiuta nella interazione tra un thread a parte e il EDT, semplicemente andando a incapsulare e nascondere il passaggio di chiamate dal thread al EDT.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

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.