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

    [JAVA] Refresh e Thread: Trappola?

    Ho una serie di contenitori annidati (JFrame->JScrollPane->JPanel->JLabel in GridLayout).

    Il contenuto delle JLabel viene preso da una query su un DB, che com'è normale che sia viene aggiornato frequentemente (nell'ordine di secondi).

    Di conseguenza non mi basta caricare le JLabel all'apertura del JFrame; ho la necessità di aggiornarle ogni 15 secondi per esempio.

    Il fatto è che se io metto TUTTO il costruttore del JFrame, dove specifico interamente la mia applicazione dentro un

    codice:
    while (true)
    {
        // COSTRUTTORE
    
        Thread.sleep (15000);
        
        // CANCELLO COSTRUTTORE
    }
    La finestra non mi viene MAI visualizzata, perchè tecnicamente non è usufruibile in quanto il ciclo è infinito...
    Insomma, come posso fare per ricaricare un pò tutto il mio JFrame ogni 15 secondi?
    Su una cosa penso non abbia molta scelta, ovvero l'utilizzo del Thread, ma.. COME USARLO senza rimanere intrappolati???

    Grazie...

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

    Re: [JAVA] Refresh e Thread: Trappola?

    Originariamente inviato da Gil1688
    Insomma, come posso fare per ricaricare un pò tutto il mio JFrame ogni 15 secondi?
    Su una cosa penso non abbia molta scelta, ovvero l'utilizzo del Thread, ma.. COME USARLO senza rimanere intrappolati???
    Sì un thread separato è la soluzione giusta per l'accesso al DB.
    E per evitare "trappole" (subdole) il concetto importante da sapere è che l'accesso alla interfaccia grafica (salvo pochi casi documentati) va fatto sempre e solo nel contesto del EDT (Event Dispatch Thread), non nel contesto di un altro thread.

    Ah, e c'è anche un altro concetto importante per evitare trappolone ancora più grosse. Il EDT non va mai tenuto "impegnato" con del proprio codice per troppo tempo, altrimenti la interfaccia utente risulta "congelata" in quel frangente di tempo.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  3. #3
    Uhm... Teoricamente ho capito, in pratica come lo implemento? Non ho tutta questa familiarietà coi thread... Consideriamo le mie classi:

    codice:
    public class Finestra extends JFrame
    {
        public Finestra
        {
            // BLA BLA BLA
        }
    }
    Che rappresenta una mia "generica" finestra, e

    codice:
    public class App extends Finestra
    {
        public App
        {
            //COSTRUISCO LO JSCROLLPANE E IL JPANEL
            //METTO UNA JLABEL IN OGNI RIGA DEL GRIDLAYOUT DEL JPANEL
            //CARICO IL CONTENUTO DELLE JLABEL DA UN DB
        }
    }
    Che la sfrutta per la mia App, vi ho risparmiato i dettagli, esattamente dove e come posso inserire questo thread che mi ricarica il JPanel ogni 15 secondi?
    Consideriamo che non dovrà mai fermarsi, io avevo pensato di mettere una chiamata a sleep (15000) in un ciclo infinito, ma così facendo cado dalla padella alla brace, in quanto l'App non è mai libera di essere usata!

    Allora io inizializzo un nuovo Thread prova = new Thread (); così facendo "credo" di simulare un multithreading, in cui lo svolgimento dell'App va avanti per conto suo, e quello della variabile "prova" non terminerà mai, ma il fatto è che non sò proprio dove inserirlo....

    Consiglio?

  4. #4
    Perdonate il doppio post, ho risolto il mio quesito e volevo scrivere la soluzione, aiutando magari chi in futuro ne avrà bisogno. Mi è bastata un minimo di teoria dei Thread e ho risolto il problema.

    Purtroppo la classe Swing è NOT THREAD SAFE, perciò non posso utilizzare il reference in esecuzione in automatico. Ma è presto risolto il problema, è bastato implementare la classe Runnable e ridefinire il metodo run nel seguente modo:

    codice:
    public class App extends Finestra implements Runnable
    {
        public App
        {
            Thread figlio = new Thread (this, "Thread figlio");
            //COSTRUISCO LO JSCROLLPANE E IL JPANEL
            //METTO UNA JLABEL IN OGNI RIGA DEL GRIDLAYOUT DEL JPANEL
            //CARICO IL CONTENUTO DELLE JLABEL DA UN DB
            figlio.start ();
        }
    
        public void run ()
        {
            while (true)
            {
                Thread.sleep (15000);
                //OPERAZIONI DI AGGIORNAMENTO JLABEL
            }
        }
    }
    Così facendo l'EDT non viene proprio toccato e porta al termine al sua esecuzione senza problemi; lasciando al povero figlio il compito di lavorare per tutta la sua esistenza all'aggiornamento di App, senza mai morire.

    Un pò brutale, ma semplice, e soprattutto FUNZIONANTE

    Un ringraziamento sentito a andbin che mi ha messo sulla giusta strada, facendomi diffidare del EDT e puntando su suo figlio.

  5. #5
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Gil1688
    perciò non posso utilizzare il reference in esecuzione in automatico.
    Scusa ma questo detto così non vuol dire nulla ...

    Originariamente inviato da Gil1688
    codice:
        public void run ()
        {
            while (true)
            {
                Thread.sleep (15000);
                //OPERAZIONI DI AGGIORNAMENTO JLABEL
            }
        }
    Così facendo l'EDT non viene proprio toccato

    [...]
    facendomi diffidare del EDT e puntando su suo figlio.
    No forse non hai ancora capito. Se in quel run() fai direttamente es.:

    unaLabel.setText(.....);

    questo è inappropriato. L'accesso alla interfaccia grafica (i componenti, layout, model, ecc...) deve essere fatto nel contesto del EDT, non nel contesto di un tuo thread come hai definito sopra.
    Salvo casi particolari (e che sono ampiamente documentati) in cui da un qualunque thread puoi invocare un certo metodo di un componente o altra classe della GUI che la documentazione (javadoc, articolo o altro di ufficiale) lo segnala come "thread safe" (tanto per dirne una: il repaint() di ogni componente).

    Prima di giungere a conclusioni affrettate e forse sbagliate, verifica bene e documentati. E se proprio hai dubbi .... chiedi!
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  6. #6
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157

    Re: [JAVA] Refresh e Thread: Trappola?

    Originariamente inviato da Gil1688
    Ho una serie di contenitori annidati (JFrame->JScrollPane->JPanel->JLabel in GridLayout).

    Il contenuto delle JLabel viene preso da una query su un DB, che com'è normale che sia viene aggiornato frequentemente (nell'ordine di secondi).

    Di conseguenza non mi basta caricare le JLabel all'apertura del JFrame; ho la necessità di aggiornarle ogni 15 secondi per esempio.

    Il fatto è che se io metto TUTTO il costruttore del JFrame, dove specifico interamente la mia applicazione dentro un

    codice:
    while (true)
    {
        // COSTRUTTORE
    
        Thread.sleep (15000);
        
        // CANCELLO COSTRUTTORE
    }
    La finestra non mi viene MAI visualizzata, perchè tecnicamente non è usufruibile in quanto il ciclo è infinito...
    Insomma, come posso fare per ricaricare un pò tutto il mio JFrame ogni 15 secondi?
    Su una cosa penso non abbia molta scelta, ovvero l'utilizzo del Thread, ma.. COME USARLO senza rimanere intrappolati???

    Grazie...
    dovresti fare 2 cose: fare un primo caricamento fuori dal costruttore (iniziale per intenderci), metti in una lista, mappa quello che vuoi e istanzi il costruttore con quello. Difficilmente perdi un update (a meno che non hai milioni di dati da elaborare) e non hai caricato il costruttore con codice che non gli pertiene.
    Di contro avvii un thread che lavora da demone e fa il tuo sporco lavoro di update dal db. Quando hai disponibili dei dati, generi un evento, il quale andrà a richiedere all'EDT l'update grafico dei dati.
    Per me è il modo più ordinato di fare le cose.
    RTFM Read That F*** Manual!!!

  7. #7
    Rispondo ad entambi...
    Ad andbin dico che nel metodo run ridefinito NON ho scritto nulla del tipo

    variabile.setText ("blabla");

    Nel mio metodo costruttore non faccio altro che creare il mio JFrame facendo delle chiamate a metodi separati, i quali uno dopo l'altro compongono tutta la finestra. Così come la finestra non viene direttamente composta nel costruttore, ma nei metodi chiamati da questo, anche le operazioni di aggiornamento non sono direttamente scritte nel costruttore, ma in appositi metodo chiamati da questo.

    Inoltre queste operazioni di aggiornamento NON vanno a modificare il contenuto di determinati oggetti, ma li ridisegnano proprio. Io non ho JLabel da modificare, ma JLabel da aggiungere con nuovi contenuti, e da aggiungere come e quando voglio io, perciò l'aggiornamento consiste in un removeAll () al pannello, un clear () alla LinkedList<JLabel> che mi mantiene le etichette, ed in una nuova query al DB, seguita da degli LinkedListReference.add (JLabel) che me le riaggiunge nel modo in cui preferisco.

    E l'App mi svolge tutto il lavoro a meraviglia, in quanto nella sua apertura il costruttore chiama dei metodi che mi costruiscono la finestra, e nel thread figlio vengono chiamati dei metodi che me la aggiornano (in realtà è uno solamente). E il thread figlio rimane intrappolato nel ciclo infinito del suo run, perciò mi aggiorna la finestra ogni 15 secondi all'infinito...

    Il modo che ho implementato mi sembra che non va troppo a sbattere con le raccomandazioni di andbin e con le dritte di valia... Devo essere sincero però, mentre sono sicuro che clear () e add () non mi creano problemi nel thread, in quanto sono metodi della classe LinkedList, non posso dire la stessa identica cosa dei metodi removeAll () e add () della classe JPanel.

    Ma ho testato l'App in milioni di modi diversi e di occasioni diverse, e finora non mi ha dato nessun problema... Ogni cosa viene svolta regolarmente e mi viene finalmente aggiornata la pagina senza mai mezza sbavatura, rallentamento o blocco...

    Alla luce di quello che ho scritto, dite che è ben o mal implementato?

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da Gil1688
    Ad andbin dico che nel metodo run ridefinito NON ho scritto nulla del tipo

    variabile.setText ("blabla");
    Io ho parlato di "direttamente" (mi scuso se è stato equivocato) ma il termine era riferito non tanto al fatto che il setText fosse materialmente dentro al while nel run ma che il setText fosse eseguito direttamente all'interno del flusso del thread!

    Originariamente inviato da Gil1688
    thread figlio vengono chiamati dei metodi che me la aggiornano (in realtà è uno solamente).
    Il punto è questo e lo ripeto ancora una volta: se nel "flusso" di esecuzione del thread secondario che tu hai creato, fai direttamente nel run o indirettamente in qualunque metodo invocato dal run dei: setText, removeAll, add (es. su contenitori), setLayout, ecc... e qualunque altro metodo tipico della interfaccia utente, questo è, lo ripeto ancora, inappropriato.

    codice:
    public void run() {
        while (true) {
            ....
            unaLabel.setText(....);    // inappropriato
            unPannello.add(altraLabel);    // inappropriato
            ....
            pippo();
            ....
        }
    }
    
    private void pippo() {
        unaLabel.setText(....);    // inappropriato (è invocato nel flusso del thread secondario)
        unPannello.add(altraLabel);    // inappropriato (idem)
    }
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  9. #9
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    scusa una considerazione: se devi aggiungere/rimuovere JLabel runtime, perchè non usi una JList o una JEditorPane?
    L'idea è di avere un componente a cui appendi stringhe (o cmq cambi il contenuto runtime) SENZA modificare di volta in volta il pannello (e non sono sicurissima che nel lungo periodo aggingi/rimuovi elementi di continuo non creino problemi, bisognerebbe testare nel caso peggiore)

    Inoltre, come più volte ti ha detto andbin, gli aggiornamenti grafici andrebbero fatti tramite EDT (quindi una gestione dei thread fatta come si deve e se implementi bene il meccanismo di eventi la raggiungi)
    RTFM Read That F*** Manual!!!

  10. #10
    Quali sono le conseguenze in cui posso incorrere nel fare un uso inappropriato dei thread, come sto facendo?

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.