Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 12
  1. #1
    Utente di HTML.it L'avatar di mbb
    Registrato dal
    Jul 2010
    Messaggi
    7

    Interfaccia si blocca quando fa partire un thread, per tutta la sua durata

    Salve il mio problema è proprio questo: ho un bottone "comincia" e uno "stop", ma il pulsante di stop è inutilizzabile, perché quando viene premuto il pulsante comincia, fino alla fine del thread tutte le interfacce, perfino seconde finestre.

    Eppure ho usato i thread, t1 è un thread e l'interfaccia stessa è un altro thread. Com'è possibile?

    Ho anche usato invokeLater che mi hanno detto dovrebbe risolvere il problema, ma non ho capito bene come funziona.

    Il resto del codice non ha nulla di significativo, se c'è bisogno chiedete pure...
    Queste sono inner class nella classe dell'interfaccia.
    codice:
    public class ApriListener implements ActionListener{		
    		private File scelta;
    		public void actionPerformed(ActionEvent e){
    			sceltafile.setVisible(true);
    			if ((sceltafile.getFile())!=null)
    				scelta = new File(sceltafile.getDirectory() + "/" + sceltafile.getFile());
    		t1=new Riproduzione (scelta);
    		t1.start();
    		}
    }
    	
    public class ChiudiListener implements ActionListener{		
    		public void actionPerformed(ActionEvent e){
    		t1.fermati();
    		}
    }
    	
    public class CominciaListener implements ActionListener{		
    		public void actionPerformed(ActionEvent e){
    		    SwingUtilities.invokeLater(new Runnable() {
    			    public void run() {
    			     t1.comincia();
    			    }
    			   });
    		//t1.comincia();
    		}
    }

  2. #2
    Utente di HTML.it L'avatar di desa
    Registrato dal
    Oct 2008
    Messaggi
    569
    Direi che dovresti postare anche il codice della classe Riproduzione... non è che fai qualcosa di bloccante nel costruttore?

  3. #3
    Utente di HTML.it L'avatar di mbb
    Registrato dal
    Jul 2010
    Messaggi
    7
    Originariamente inviato da desa
    Direi che dovresti postare anche il codice della classe Riproduzione... non è che fai qualcosa di bloccante nel costruttore?
    no, perché la classe riproduzione riproduce un wav che attualmente dura 3 secondi, si sente il suono dopodiché il thread finisce regolarmente e i bottoni tornano funzionanti.

    ps: il costruttore è questo
    codice:
     
    public Riproduzione (File percorso){
    	f=percorso;
    }

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

    Re: Interfaccia si blocca quando fa partire un thread, per tutta la sua durata

    Originariamente inviato da mbb
    Ho anche usato invokeLater che mi hanno detto dovrebbe risolvere il problema, ma non ho capito bene come funziona.

    codice:
    		    SwingUtilities.invokeLater(new Runnable() {
    			    public void run() {
    			     t1.comincia();
    			    }
    			   });
    invokeLater fa 1 cosa ben precisa: "deposita" il Runnable (l'argomento passato) in una "coda" e il run() verrà eseguito nel contesto del EDT (questo è il punto fondamentale/cruciale!) appena possibile, ovvero quando il controllo è ritornato al framework (quindi sicuramente dopo che actionPerformed è terminato) e si scopre che c'è questo Runnable da eseguire tirando fuori ciò che c'è in coda.

    Cosa fa comincia()??? Se fa qualcosa di lungo ... allora sta tenendo "impegnato" il EDT. Questa sarebbe la spiegazione del blocco.
    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 desa
    Registrato dal
    Oct 2008
    Messaggi
    569
    E Riproduzione estende Thread?
    Fai in modo di invocare il metodo start() di Thread, se ridefinito?
    Ridefinisci il metodo run()?

  6. #6
    Utente di HTML.it L'avatar di mbb
    Registrato dal
    Jul 2010
    Messaggi
    7
    Originariamente inviato da desa
    E Riproduzione estende Thread?
    Fai in modo di invocare il metodo start() di Thread, se ridefinito?
    Ridefinisci il metodo run()?
    Riproduzione estende Thread.
    Ridefinisco run e invoco start.

    Ma questo si capiva già dal codice...

    Comincia ho già detto che suona un breve wav, e mentre lo suona l'interfaccia non risponde.

    invokeLater l'ho messo per provare a risolvere il problema, senza invokeLater il programma si comportava esattamente nello stesso modo...

  7. #7
    Utente di HTML.it L'avatar di mbb
    Registrato dal
    Jul 2010
    Messaggi
    7
    tutto il codice, se ci giochiamo assieme impariamo qualcosa o almeno io...



    Test.java
    codice:
    package audio;
    
    public class Test {
    	public static void main(String[] args) {
    		Finestra windows = new Finestra();
    		windows.start();
    	}
    }
    Finestra.java
    codice:
    package audio;
    
    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.*;
    import java.io.*;
    
    public class Finestra extends Thread {
    	private JFrame frame;
    	private FileDialog sceltafile;
    	private JFrame dialogsceltafile;
    	private JButton bottonestop;
    	private JButton bottoneapri;
    	private JButton bottonecomincia;
    	Riproduzione t1;
    	
    	public Finestra () {
    		frame = new JFrame ("APF");
    		bottoneapri = new JButton ("Apri");
    		bottonecomincia = new JButton ("Comincia");
    		bottonestop = new JButton ("Stop");
    		dialogsceltafile = new JFrame ();
    		sceltafile = new FileDialog (dialogsceltafile);
    	}
    	
    	public void run(){
    		bottoneapri.addActionListener(new ApriListener());
    		bottonecomincia.addActionListener(new CominciaListener());
    		bottonecomincia.addActionListener(new CominciaListener());
    		bottonestop.addActionListener(new ChiudiListener());
    		frame.add(bottonestop);
    		frame.add(bottoneapri);
    		frame.add(bottonecomincia);
    		frame.setLayout(new FlowLayout());
    		frame.setSize(400, 300);
    		frame.setVisible(true);
    	}
    	
    	public class ApriListener implements ActionListener{		
    		private File scelta;
    		public void actionPerformed(ActionEvent e){
    			sceltafile.setVisible(true);
    			if ((sceltafile.getFile())!=null)
    				scelta = new File(sceltafile.getDirectory() + "/" + sceltafile.getFile());
    		t1=new Riproduzione (scelta);
    		t1.start();
    		}
    	}
    	
    	public class ChiudiListener implements ActionListener{		
    		public void actionPerformed(ActionEvent e){
    		t1.fermati();
    		}
    	}
    	
    	public class CominciaListener implements ActionListener{		
    		public void actionPerformed(ActionEvent e){ 
    		t1.comincia();
    		}
    	}
    }
    Riproduzione.java
    codice:
    package audio;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    import javax.sound.sampled.AudioFormat;
    import javax.sound.sampled.AudioInputStream;
    import javax.sound.sampled.AudioSystem;
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.SourceDataLine;
    import javax.sound.sampled.UnsupportedAudioFileException;
    
    public class Riproduzione extends Thread {
        private File f;
        private SourceDataLine sdl=null;
        private static final int EXTERNAL_BUFFER = 128000;
        private byte[] data = new byte[EXTERNAL_BUFFER];
        private AudioFormat af=null;
        private AudioInputStream ais=null;
        private Boolean stopped=false;
        
        public Riproduzione (File percorso){
    	f=percorso;
        }
        
        
        
        public void run () {
    	try {
    	    ais = AudioSystem.getAudioInputStream(f);
    	    af = AudioSystem.getAudioFileFormat(f).getFormat();
    	    sdl = AudioSystem.getSourceDataLine(af);
    	    sdl.open(af);
    	}
    
    	catch (FileNotFoundException e) {
    	    // TODO Auto-generated catch block
    	    e.printStackTrace();
    	} catch (UnsupportedAudioFileException e) {
    	    // TODO Auto-generated catch block
    	    e.printStackTrace();
    	} catch (IOException e) {
    	    // TODO Auto-generated catch block
    	    e.printStackTrace();
    	} catch (LineUnavailableException e) {
    	    // TODO Auto-generated catch block
    	    e.printStackTrace();
    	}
        }
        
        public void comincia(){
    	sdl.start();
    	    int BytesRead = 0;
    	    while (BytesRead != -1 && !stopped) {
    		try {
    		    BytesRead = ais.read(data, 0, EXTERNAL_BUFFER);
    		} catch (IOException e) {
    		    e.printStackTrace();
    		}
    		if (BytesRead >= 0) {
    		    sdl.write(data, 0, BytesRead);
    		}
    	    }
    	    sdl.drain();
    	    sdl.close();
        }
        
        
        public void fermati(){
    	sdl.stop();
    	stopped=true;
        }
    }
    Si accettano consigli di ogni tipo tranne "commentalo", è una cosa che faccio se il codice funziona. Inoltre il ciclo sembra terminare regolarmente, e appena finisce la riproduzione i pulsanti rispondono di nuovo.

    ps. visto che la Java Sound di default supporta solo alcuni, pochi, tipi di wav, suggerisco uno dei primi due clip di questo sito per provare il programma, che si sentono...
    http://www.talkingwav.com/cartoon_wav_sounds.html

  8. #8
    Utente di HTML.it L'avatar di andbin
    Registrato dal
    Jan 2006
    residenza
    Italy
    Messaggi
    18,284
    Originariamente inviato da mbb
    tutto il codice

    Si accettano consigli di ogni tipo tranne "commentalo"
    La mia idea/supposizione l'avevo detta .... e ora con l'intero codice visibile ne ho piena conferma.

    Il metodo comincia() compie il "lungo" lavoro di lettura e riproduzione. Tu lo fai partire dal actionPerformed(). Che tu usi invokeLater oppure no non cambia appunto nulla e ottieni sempre il blocco perché:

    a) actionPerformed è invocato nel contesto del EDT. Se invochi direttamente comincia() lo fai in modo sincrono nel momento stesso dell'evento. E tieni "impegnato" il EDT.

    b) Se usi invokeLater, la esecuzione di actionPerformed dura pochissimo (invokeLater "parcheggia" solo il Runnable in coda) ma il run() (e quindi il comincia() contenuto) saranno eseguiti solo un pochino dopo, per così dire in "differita" ma comunque nuovamente nel contesto del EDT.

    Ripeto: in ogni caso stai tenendo impegnato il EDT e quindi la interfaccia resta "congelata" in tutto quel frangente di tempo.

    Non ha senso che hai fatto il Thread solo per eseguire quelle inizializzazioni/aperture che in linea di massima non ci mettono granché come tempo.

    Devi fare in modo che quando vuoi far partire il suono, tutta la gestione, dalla apertura, lettura/riproduzione, alla chiusura venga fatta in un thread separato!!


    Se ora hai compreso .... bene.
    Andrea, andbin.devSenior Java developerSCJP 5 (91%) • SCWCD 5 (94%)
    java.util.function Interfaces Cheat SheetJava Versions Cheat Sheet

  9. #9
    [ot]
    Secondo me la versione del forum che ha andbin ha il bottone per far uscire

    stai tenendo impegnato il EDT

    senza doverlo scrivere un post si' e uno no

    [/ot]
    max

    Silence is better than bullshit.
    @mmarcon
    jHERE, Maps made easy

  10. #10
    Utente di HTML.it L'avatar di mbb
    Registrato dal
    Jul 2010
    Messaggi
    7
    Originariamente inviato da andbin
    La mia idea/supposizione l'avevo detta .... e ora con l'intero codice visibile ne ho piena conferma.
    per me extends thread era una magia, pensavo che tutti i metodi fossero gestiti miracolosamente, invece tutti i metodi diversi da run si comportano nello stesso modo di come si comporterebbero in qualsiasi altra classe. ( giusto? )

    Non ha senso che hai fatto il Thread solo per eseguire quelle inizializzazioni/aperture che in linea di massima non ci mettono granché come tempo.

    Devi fare in modo che quando vuoi far partire il suono, tutta la gestione, dalla apertura, lettura/riproduzione, alla chiusura venga fatta in un thread separato!!
    ho fatto nel modo seguente, l'interfaccia risponde e il suono si sente, ma l'invocazione di start (che ora è associata al pulsante comincia) fa partire una IllegalThreadStateException.

    In thread.class leggo: «A zero status value corresponds to state "NEW"», FORSE mi vuole dire che non posso applicare altri metodi di una classe che estende thread prima di invocare start ( giusto? ). Però non lo faccio, o non vedo dove lo faccio, invoco solo il costruttore: il costruttore fa "troppe" cose?
    Il punto è il percorso da qualche parte ce lo devo pure passare a sto thread, in alternativa dove cavolo glielo passo, visto che il metodo start non accetta parametri?

    Riproduzione.java
    codice:
        public Riproduzione (File percorso) {
    	f=percorso;
    	try {
    	    ais = AudioSystem.getAudioInputStream(f);
    	    af = AudioSystem.getAudioFileFormat(f).getFormat();
    	    sdl = AudioSystem.getSourceDataLine(af);
    	    sdl.open(af);
    	}
    
    	catch (FileNotFoundException e) {
    	    // TODO Auto-generated catch block
    	    e.printStackTrace();
    	} catch (UnsupportedAudioFileException e) {
    	    // TODO Auto-generated catch block
    	    e.printStackTrace();
    	} catch (IOException e) {
    	    // TODO Auto-generated catch block
    	    e.printStackTrace();
    	} catch (LineUnavailableException e) {
    	    // TODO Auto-generated catch block
    	    e.printStackTrace();
    	}
        }
        
        public void run(){
    	sdl.start();
    	    int BytesRead = 0;
    	    while (BytesRead != -1 && !stopped) {
    		
    		try {
    		    BytesRead = ais.read(data, 0, EXTERNAL_BUFFER);
    		} catch (IOException e) {
    		    e.printStackTrace();
    		}
    		if (BytesRead >= 0) {
    		    sdl.write(data, 0, BytesRead);
    		}
    	    }
    	    sdl.drain();
    	    sdl.close();
        }
        
        
        public void fermati(){
    	sdl.stop();
    	stopped=true;
        }
    e in Finestra.java gli ActionListener così
    public class ApriListener implements ActionListener{
    private File scelta;
    public void actionPerformed(ActionEvent e){
    sceltafile.setVisible(true);
    if ((sceltafile.getFile())!=null)
    scelta = new File(sceltafile.getDirectory() + "/" + sceltafile.getFile());
    t1=new Riproduzione (scelta);
    }
    }

    public class ChiudiListener implements ActionListener{
    public void actionPerformed(ActionEvent e){
    t1.fermati();
    }
    }

    public class CominciaListener implements ActionListener{
    public void actionPerformed(ActionEvent e){
    t1.start();
    }
    }
    Se ora hai compreso .... bene.
    Come vedi...

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.