Visualizzazione dei risultati da 1 a 6 su 6
  1. #1
    Utente di HTML.it
    Registrato dal
    Jan 2010
    Messaggi
    111

    Threads e Swing ( Gui )

    Ragazzi ho questo problema, praticamente ho creato un'interfaccia grafica molto articolata, all'interno di questa interfaccia grafica, c'è una jcombobox che deve caricare oltre 1000 voci, ovviamente questo caricamento deve avvenire mentre l'utente compila le altre parti della stessa interfaccia grafica. Ho provato a realizzare il caricamento di questa jcomboBox in un thread, ma sia con il thread che senza, la gui si blocca per alcuni istanti di tempo ritornando utilizzabile solo alla fine del caricammento delle 1000 voci. Come posso risolvere? Grazie mille
    Si vis Pacem Para Bellum

  2. #2
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284

    Re: Threads e Swing ( Gui )

    Originariamente inviato da Lord112
    Ragazzi ho questo problema, praticamente ho creato un'interfaccia grafica molto articolata, all'interno di questa interfaccia grafica, c'è una jcombobox che deve caricare oltre 1000 voci, ovviamente questo caricamento deve avvenire mentre l'utente compila le altre parti della stessa interfaccia grafica. Ho provato a realizzare il caricamento di questa jcomboBox in un thread, ma sia con il thread che senza, la gui si blocca per alcuni istanti di tempo ritornando utilizzabile solo alla fine del caricammento delle 1000 voci. Come posso risolvere? Grazie mille
    Guarda/prova questo. Vedrai non solo che ci mette un po' (causa lo sleep) a caricare i 1000 elementi (e vedrai la scrollbar che cambia man mano) ma anche che la interfaccia è perfettamente responsiva.

    codice:
    import java.awt.*;
    import javax.swing.*;
    
    public class LoadingComboTest {
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new LoadingComboTestFrame().setVisible(true);
                }
            });
        }
    }
    
    
    class LoadingComboTestFrame extends JFrame {
        private DefaultComboBoxModel<String> comboModel;
        private JComboBox<String> comboBox;
    
        public LoadingComboTestFrame() {
            super("Loading Combo Test");
    
            setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            setSize(300, 250);
    
            comboModel = new DefaultComboBoxModel<String>();
            comboBox = new JComboBox<String>(comboModel);
    
            getContentPane().add(comboBox, BorderLayout.NORTH);
    
            Thread t = new Thread(new ComboLoader(comboModel));
            t.start();
        }
    }
    
    
    class ComboLoader implements Runnable {
        private DefaultComboBoxModel<String> comboModel;
    
        public ComboLoader(DefaultComboBoxModel<String> comboModel) {
            this.comboModel = comboModel;
        }
    
        public void run() {
            try {
                for (int i = 0; i < 1000; i++) {
                    final String elem = "elemento " + (i+1);
    
                    // Questo è fondamentale per far "passare" il addElement nel EDT.
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            comboModel.addElement(elem);
                        }
                    });
    
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    P.S. DefaultComboBoxModel/JComboBox sono "tipizzati" perché queste classi sono generiche da Java 7.
    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
    Registrato dal
    Jan 2010
    Messaggi
    111
    Ti ringrazio del suggerimento, ma la cosa continua a non funzionare, ho esattamente fatto tutto quello che mi hai indicato tu ( ovviamente adattandolo al mio caso ), ma il risultato è sempre lo stesso e la cosa mi sta facendo davvero impazzire.

    Ti chiedo qualche chiarimento così vediamo di trovare l'errore nel mio codice, premetto che tutte le mie classi sono distribuite in file diversi, quindi io le richiamo dopo aver premuto un JButton. Passiamo ai chiarimenti:

    1- Perchè nel momento in cui vai ad aprire la finestra grafica la apri in questo modo?
    codice:
    SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new LoadingComboTestFrame().setVisible(true);
                }
            });
    Io che ho già diverse finestre grafiche aperte, quando vado a richiamare questa finestra ( che nel mio caso è un JDialog ) che contiene la ComboBox da popolare, la devo richiamare comunque in questo modo?

    2- Perchè nel metodo RUN richiami nuovamene l'invokeLater?

    Resto in attesa di una tua risposta, con l'occasione ti auguro una buone e felice giornata.
    Si vis Pacem Para Bellum

  4. #4
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Lord112
    1- Perchè nel momento in cui vai ad aprire la finestra grafica la apri in questo modo?
    codice:
    SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new LoadingComboTestFrame().setVisible(true);
                }
            });
    Questo, tipicamente nel main(), è semplicemente la "buona" pratica di far partire il tutto, fin dall'inizio con la prima finestra, nel contesto del EDT.

    Originariamente inviato da Lord112
    Io che ho già diverse finestre grafiche aperte, quando vado a richiamare questa finestra ( che nel mio caso è un JDialog ) che contiene la ComboBox da popolare, la devo richiamare comunque in questo modo?
    No, se ad esempio sei in un actionPerformed() (es. ActionListener registrato su un JButton) questo è invocato dal framework nel contesto del EDT, quindi se a seguito del click sul pulsante vuoi istanziare/visualizzare un JDialog allora puoi farlo direttamente.

    Originariamente inviato da Lord112
    2- Perchè nel metodo RUN richiami nuovamene l'invokeLater?
    Perché il run di ComboLoader "gira" nel contesto di nuovo thread a parte (creato e avviato in LoadingComboTestFrame) che non è ovviamente il EDT e quindi non deve accedere alla interfaccia utente. Pertanto passo al framework un Runnable che verrà eseguito (il suo run() ) "appena possibile" nel contesto del EDT per aggiornare la interfaccia utente.


    P.S. mi sorge un dubbio a questo punto: che non hai ancora compreso il "threading" in Swing.
    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
    Registrato dal
    Jan 2010
    Messaggi
    111
    Ciao, grazie mille per tutto il supporto che mi stai dando, diciamo che il Threading di swing non mi è chiarissimo, perchè non è da molto che mi approccio ad esso ( ) , in generale ho sempre usato thread per fare calcoli ma mai per mostrare cose su gui...
    Allora ti posto pari pari quello che sto cercando di fare:

    1- Questo è il codice che eseguo per richiamare la mia finestra con la combobox ed altra roba ( è un jframe per comodità di test ), questo codice viene eseguito quando premo su un bottone ( Avvia visualizzazione )

    codice:
    TEST a=new TEST();
           a.setVisible(true);
    2- A questo punto, siccome io voglio che al caricamento di "a" , la combobox venga popolata, richiamo il thread con l'azione " formComponentShown " e nel corpo di questo evento metto:


    codice:
    CaricaComuniThreads caricaComuni;
            try {
                caricaComuni = new CaricaComuniThreads(jComboBox1, Main.getConnessioneDB());
                Thread t = new Thread(caricaComuni);
                t.start();
    
            } catch (SQLException ex) {
                Logger.getLogger(TEST.class.getName()).log(Level.SEVERE, null, ex);
            }
    3- La classe caricaComuni è così fatta( solo il metodo run () per ovvi motivi di spazio ):
    codice:
    @Override
        public void run() {
            for (int i = 0; i < nomiComuni.size(); i++) {
                final String elem=nomiComuni.get(i);
                SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                           comboBoxComuni.addItem(elem);
                        }
                    });
     
            }
        }
    Quando eseguo questo "casotto" la gui si blocca sempre, per ritornare funzionante solo dopo aver completato il caricamento di tutti i comuni. Cosa sbaglio? Non dovrei far eseguire il codice nell'evento " formComponentShown "??
    Grazie mille per tutto il supporto che mi stai dando.
    Si vis Pacem Para Bellum

  6. #6
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Lord112
    codice:
    CaricaComuniThreads caricaComuni;
            try {
                caricaComuni = new CaricaComuniThreads(jComboBox1, Main.getConnessioneDB());
                Thread t = new Thread(caricaComuni);
                t.start();
    
            } catch (SQLException ex) {
                Logger.getLogger(TEST.class.getName()).log(Level.SEVERE, null, ex);
            }
    3- La classe caricaComuni è così fatta( solo il metodo run () per ovvi motivi di spazio ):
    codice:
    @Override
        public void run() {
            for (int i = 0; i < nomiComuni.size(); i++) {
                final String elem=nomiComuni.get(i);
                SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                           comboBoxComuni.addItem(elem);
                        }
                    });
     
            }
        }
    Quando eseguo questo "casotto" la gui si blocca sempre, per ritornare funzionante solo dopo aver completato il caricamento di tutti i comuni. Cosa sbaglio? Non dovrei far eseguire il codice nell'evento " formComponentShown "??
    Grazie mille per tutto il supporto che mi stai dando.
    I pezzi di codice che hai postato, solo a vederlì così, sembrerebbero a posto. Cioè da queste righe non si nota nulla di palesemente errato.

    Ma ... in queste righe che hai postato non si vede la parte che materialmente carica i dati da db. Quello che si vede solo è:

    caricaComuni = new CaricaComuniThreads(jComboBox1, Main.getConnessioneDB());

    E quindi mi sorge spontanea la domanda: il caricamento da DB lo fai nel costruttore di CaricaComuniThreads??
    Perché se lo fai lì .... mi sembra ovvio che lo stai facendo ancora nel contesto del EDT, non hai ancora fatto istanziare/partire il nuovo thread!
    E se lo fai nel contesto del EDT, di conseguenza tiene bloccata la interfaccia utente.
    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.