[Resolvido]Duvida com Threads

7 respostas
Bruno_Ferreira1

Estou desenvolvendo um discador em Java (De conexão discada mesmo), e consigo passar comandos para o prompt através do RunTime.getRunTime.exec().
Com isso consigo realizar a discagem de um número pré configurado.
Mas eu utilizo um objeto Scanner para pegar a saida do prompt

Scanner s = new Scanner(RunTime.getRunTime.exec(comando).getOutputStream());

é mais ou menos isso, não lembro bem, pois esta em outro pc
e funciona, ele pega a saída do prompt.
Eu quero usar isto pra mostrar o status num label que tem no JFrame
então eu pego o texto deste objeto Scanner e jogo no setText do JLabel

Se eu faço o comando no DOS, ele mostra: “Conectando.” “Conectando…” “Conectando…” “Conectando…”
e ai se conectar ele mostra: “Conectado”.
Ou se der erro ele aparece: “Conectando.” “Conectando…” “Conectando…” “Conectando…” “Erro650, blablablabla”

mas na aplicação em java, ele fica esperando acabar todo o comando, pra depois mostrar a saída toda de uma vez, tipo quando eu clico
no botão conectar, a aplicação da uma “travada”, esperando terminar todo o comando, pra depois mostrar a saída toda de uma vez
uns 10 segundos depois ja aparece tudo de uma vez:
“Conectando.” “Conectando…” “Conectando…” “Conectando…” “Erro650, blablablabla”

queria que o texto do Label fosse atualizado de tempo em tempo, tipo mostrar o “conectando” e depois quando desse o erro mostrasse o erro
e não ele ficar “travado” esperando toda a execução do comando e mudar o texto do Label todo de uma vez

Será que é possível resolver isso com Threads?

Agradeço pela ajuda

7 Respostas

ViniGodoy

Sim, no tópico abaixo existe uma classe para redirecionar o stream do processo a outro stream, através de uma thread:

E aqui mostra como redirecionar o texto de um Stream para um JTextArea:

Bruno_Ferreira1

Muito obrigado Vini, só pude ver a mensagem agora, vou testar aqui e posto o resultado :smiley:

Bruno_Ferreira1
ViniGodoy:
Sim, no tópico abaixo existe uma classe para redirecionar o stream do processo a outro stream, através de uma thread: http://www.guj.com.br/java/213361-processbuilder#1087285

E aqui mostra como redirecionar o texto de um Stream para um JTextArea:
http://www.guj.com.br/java/83462-ajuda-com-um-jtextarea-especial#445260

então Vini, não sei se eu fiz errado, mas não funcionou, tirei a parte que eu estava usando para setar o texto da JTextArea:

try {                  
                StringBuilder texto=new StringBuilder();
                Runtime rt = Runtime.getRuntime(); 
                Process proc=rt.exec(comando);
                Scanner s = new Scanner (proc.getInputStream());                            
                while(s.hasNext()){
                    texto.append(s.nextLine());
                }     
                txt_area.setText(texto.toString);

copiei aquelas classes para o meu projeto e utilizei o código da seguinte maneira:

try {           
                Runtime rt = Runtime.getRuntime(); 
                Process proc=rt.exec(comando);                                          
                    
                 //instanciei os dois TextComponent, passando a JTextArea que deveria receber a saida do prompt como parâmetro
                 TextComponentStream t=new TextComponentStream(txt_area, null);
                 TextComponentStream t2=new TextComponentStream(txt_area, getErrorStyle());
                 System.setOut(new PrintStream(t));  
                 System.setErr(new PrintStream(t2));

                 //este parâmetro System.out do StreamRedirector serve para indicar a saída?
                 StreamRedirector red = new StreamRedirector(System.out, proc.getInputStream());
                  
                try {                    
                    proc.waitFor();                        
                } catch (InterruptedException ex) {
                    JOptionPane.showMessageDialog(rootPane, "Erro no proc.waitfor: "+ex.getMessage());
                }
                red.stopRedirect();

Mas não mudou o texto da TextArea e o programa continua dando uma "travada" até se completar o comando do DOS
Desculpe a ignorância, mas poderia me explicar melhor como executar este código?

ViniGodoy

Se você quer só redirecionar ao JTextArea, esqueça o System:

try {           
                Runtime rt = Runtime.getRuntime(); 
                Process proc=rt.exec(comando);                                          
                    
                 //Criamos um Stream que escreve num JTextArea
                 TextComponentStream t=new TextComponentStream(txt_area, null);

                 //O primeiro parâmetro indica para onde o fluxo do segundo será redirecionado
                 //Ou seja, iremos redirecionar o stream do processo para o stream que escreve no JTextArea.
                 StreamRedirector red = new StreamRedirector(t, proc.getInputStream());
                  
                try {                    
                    proc.waitFor();                        
                } catch (InterruptedException ex) {
                    JOptionPane.showMessageDialog(rootPane, "Erro no proc.waitfor: "+ex.getMessage());
                }
                red.stopRedirect();

O parâmetro de cor só funciona para JTextPane. Nesse caso, você pode também redirecionar o ErrorStream do processo para lá. Ou use o ProcessBuilder no lugar do Runtime e junte os dois streams num só.

Bruno_Ferreira1
ViniGodoy:
Se você quer só redirecionar ao JTextArea, esqueça o System:
try {           
                Runtime rt = Runtime.getRuntime(); 
                Process proc=rt.exec(comando);                                          
                    
                 //Criamos um Stream que escreve num JTextArea
                 TextComponentStream t=new TextComponentStream(txt_area, null);

                 //O primeiro parâmetro indica para onde o fluxo do segundo será redirecionado
                 //Ou seja, iremos redirecionar o stream do processo para o stream que escreve no JTextArea.
                 StreamRedirector red = new StreamRedirector(t, proc.getInputStream());
                  
                try {                    
                    proc.waitFor();                        
                } catch (InterruptedException ex) {
                    JOptionPane.showMessageDialog(rootPane, "Erro no proc.waitfor: "+ex.getMessage());
                }
                red.stopRedirect();

O parâmetro de cor só funciona para JTextPane. Nesse caso, você pode também redirecionar o ErrorStream do processo para lá. Ou use o ProcessBuilder no lugar do Runtime e junte os dois streams num só.

precisa implementar mais alguma coisa no:
try {                    
     proc.waitFor(); 
     //precisa implementar mais algo aqui?                       
}

continuo com o mesmo problema, quando clico no botão conectar o programa da uma "travada" até se encerrar o comando e o texto do JTextArea não muda com a utilização desta classe,
só muda se eu der um txt_area.setText("alguma informação");
desculpe a ignorância...

ViniGodoy

Ah, claro, seu programa trava por causa do Waitfor.

Dispare todo o código numa nova thread:

//Desabilita o botão para evitar que o usuário pressione várias vezes seguidas.
seuBotao.setEnabled(false);
new Thread(new Runnable() {
    @Override
    public void run() {
        try {             
            Runtime rt = Runtime.getRuntime();   
            Process proc=rt.exec(comando);                                            
                          
                //Criamos um Stream que escreve num JTextArea  
                TextComponentStream t=new TextComponentStream(txt_area, null);  
      
                //O primeiro parâmetro indica para onde o fluxo do segundo será redirecionado  
                //Ou seja, iremos redirecionar o stream do processo para o stream que escreve no JTextArea.  
                StreamRedirector red = new StreamRedirector(t, proc.getInputStream());  
                        
                try {                      
                    proc.waitFor();                          
                } catch (InterruptedException ex) {  
                    JOptionPane.showMessageDialog(rootPane, "Erro no proc.waitfor: "+ex.getMessage());  
                }  
                red.stopRedirect();   
                seuBotao.setEnabled(true); //Habilita depois que o programa externo finalizar
    }
}).start();
Bruno_Ferreira1
ViniGodoy:
Ah, claro, seu programa trava por causa do Waitfor.

Dispare todo o código numa nova thread:

//Desabilita o botão para evitar que o usuário pressione várias vezes seguidas.
seuBotao.setEnabled(false);
new Thread(new Runnable() {
    @Override
    public void run() {
        try {             
            Runtime rt = Runtime.getRuntime();   
            Process proc=rt.exec(comando);                                            
                          
                //Criamos um Stream que escreve num JTextArea  
                TextComponentStream t=new TextComponentStream(txt_area, null);  
      
                //O primeiro parâmetro indica para onde o fluxo do segundo será redirecionado  
                //Ou seja, iremos redirecionar o stream do processo para o stream que escreve no JTextArea.  
                StreamRedirector red = new StreamRedirector(t, proc.getInputStream());  
                        
                try {                      
                    proc.waitFor();                          
                } catch (InterruptedException ex) {  
                    JOptionPane.showMessageDialog(rootPane, "Erro no proc.waitfor: "+ex.getMessage());  
                }  
                red.stopRedirect();   
                seuBotao.setEnabled(true); //Habilita depois que o programa externo finalizar
    }
}).start();

Valeu Vini, com este último toque que você passou funcionou o que eu queria,
só não consegui fazer o redirecionamento direto para a caixa de texto, só redirecionava
as mensagens de erro do console do netbeans, que apareciam em vermelho dentro da TextArea,
conforme o TextComponentStream que usava um estilo(fonte vermelha) para os erros.
Devo ter feito alguma coisa errada, pois o TextComponentStream que deveria mostrar a mensagem na TextArea não funcionou.
Mas tudo bem, fiz uma outra função que pega a saida do prompt usando o Scanner e setando a saida para o textarea,
e ja esta funcionando do jeito que eu precisava

Muito obrigado :D

Criado 2 de julho de 2011
Ultima resposta 5 de jul. de 2011
Respostas 7
Participantes 2