Status da progressbar não atualiza

10 respostas
J

Olá pessoal, estou com uma dúvida, tomara que possam me ajudar.

Tenho uma aplicação onde executo um arquivo .bat após o usuário clicar em um botão. No momento em que esse .bat estiver executando, tenho uma progressbar e quero que ela vá se preenchendo conforme o .bat executa.
Pois bem, passo os valores pra progressbar que criei, mas ela não atualiza conforme é chamada, depois que o .bat termina, ela já aparece 100% preenchida.

Pra explicar melhor, essa é a parte onde chamo a progressbar, passando os valores para preencher:

try {
                
                while((s =result.readLine())!= null)
                {
                    
                    System.out.println(s); 
                    if("1 arquivo(s) copiado(s)".equals(s)){
                        retorno++;
                        area.append(retorno+" arquivo(s) de "+cont+" copiado(s)\n");
                                                
                        new ProgressBar().executaProgresso(progresso, retorno, cont);              
                    }
                    
                    
                }   
           }
               catch (IOException e) {
                   e.printStackTrace();
               }

e aqui a progressbar:

public class ProgressBar {
    
    JProgressBar barra;
    
    public void executaProgresso(JProgressBar progresso, final int num, final int linhas){
        this.barra = progresso;
        barra.setMinimum(0);
        barra.setMaximum(100);
        barra.setStringPainted(true);
        
        SwingWorker worker = new SwingWorker() {
        
        
            protected Object doInBackground() throws Exception {                 
            
             
               barra.setValue(Math.round((num/linhas)*100));
               Thread.sleep(20);
               System.out.println("num: "+num+"\nlinhas: "+linhas);
               
                                    
                return null;
                        
                }
            protected void done(){
                              
            }          
            
        
        };
                worker.execute();
    }
            
    
}

Reparem que dou um system.out pra ver se a classe realmente é chamada e os valores são passados corretamente, e estão sendo passados. Não sei como fazer pra progressbar atualizar em tempo de execução.

Obrigada.

10 Respostas

T

Tente alterar a linha:

barra.setValue(Math.round((num/linhas)*100));

Para:

barra.setValue(Math.round((num * 100 / linhas)));
J

t_java:
Tente alterar a linha:

barra.setValue(Math.round((num/linhas)*100));

Para:

barra.setValue(Math.round((num * 100 / linhas)));

Aí que não funcionou mesmo… o problema está em atualizar a barra enquanto o arquivo externo está em execução.
A conta que eu estou fazendo está retornando o valor correto, só que não atualiza a barra e nem o texto que estou jogando pra um JTextArea no tempo certo, só atualiza a aplicação no final da execução.

T

Realmente a fórmula que você está usando está correta, porém os tipos numéricos não estão apropriados:

public void executaProgresso(JProgressBar progresso, final int num, final int linhas){

Tanto o parâmetro num e linhas são do tipo int, portanto no momento da divisão i*100[/i] o trecho i[/i] está retornado igual a zero quando o resultado tem casas decimais (Exemplo 0,5 vira 0).
Observe, numa situação onde o número de linhas é igual a 1000 e a linha atual é igual a 500:

(500 / 1000) * 100 = (0,5) * 100, porém como inteiro não têm decimal a fórmula fica : (0) * 100 = 0

A fórmula somente funciona quando o valor de num fica igual ao de linhas:
(1000 / 1000) * 100 = (1) * 100 = 100

Tente o seguinte print para visualizar que o resultado da fórmula é sempre zero:

System.out.println(Math.round((num / linhas) * 100));

Por isso sugeri a inversão da fórmula para (num * 100 / linhas):
(500 * 100 / 1000) * 100 = (50000 / 1000) = 50

Para manter a fórmula da maneira atual i*100[/i], algum dos parametros do método teria de ser trocado por um tipo numérico que aceite casas decimais, como o float:

public void executaProgresso(JProgressBar progresso, final float num, final int linhas){
J

Valeu pela dica!
Vou testar e posto aqui o resultado.

[]

J

t_java:
Realmente a fórmula que você está usando está correta, porém os tipos numéricos não estão apropriados:

public void executaProgresso(JProgressBar progresso, final int num, final int linhas){

Tanto o parâmetro num e linhas são do tipo int, portanto no momento da divisão i*100[/i] o trecho i[/i] está retornado igual a zero quando o resultado tem casas decimais (Exemplo 0,5 vira 0).
Observe, numa situação onde o número de linhas é igual a 1000 e a linha atual é igual a 500:

(500 / 1000) * 100 = (0,5) * 100, porém como inteiro não têm decimal a fórmula fica : (0) * 100 = 0

A fórmula somente funciona quando o valor de num fica igual ao de linhas:
(1000 / 1000) * 100 = (1) * 100 = 100

Tente o seguinte print para visualizar que o resultado da fórmula é sempre zero:

System.out.println(Math.round((num / linhas) * 100));

Por isso sugeri a inversão da fórmula para (num * 100 / linhas):
(500 * 100 / 1000) * 100 = (50000 / 1000) = 50

Para manter a fórmula da maneira atual i*100[/i], algum dos parametros do método teria de ser trocado por um tipo numérico que aceite casas decimais, como o float:

public void executaProgresso(JProgressBar progresso, final float num, final int linhas){

Realmente, estava retornando 0 e agora estou fazendo assim:

protected Object doInBackground() throws Exception {                 
            
             int total = (int) ((num/linhas)*100);
             
             total = Math.round(total);
               barra.setValue(total);
                
               System.out.println("valor retorno=> "+total);
                                   
                return null;
                        
                }

Agora os valores estão sendo passados corretamente, mas tanto a progressbar, quanto as mensagens que passo para o JTextArea, continuam aparecendo na tela só no final da execução. Acho que ainda está faltando alguma coisa no código que está no botão pra fazer atualizar em tempo de execução, só não faço idéia do que.

T

Antes de você executar o .bat você consegue identificar quantas linhas ele irá gerar?

Digo isso, por que fiquei em dúvida de onde saí o valor da váriavel cont.

try {
                
                while((s =result.readLine())!= null)
                {
                    
                    System.out.println(s); 
                    if("1 arquivo(s) copiado(s)".equals(s)){
                        retorno++;
                        area.append(retorno+" arquivo(s) de "+cont+" copiado(s)\n");
                                                
                        new ProgressBar().executaProgresso(progresso, retorno, cont);              
                    }
                    
                    
                }   
           }
               catch (IOException e) {
                   e.printStackTrace();
               }
J

t_java:
Antes de você executar o .bat você consegue identificar quantas linhas ele irá gerar?

Digo isso, por que fiquei em dúvida de onde saí o valor da váriavel cont.

try {
                
                while((s =result.readLine())!= null)
                {
                    
                    System.out.println(s); 
                    if("1 arquivo(s) copiado(s)".equals(s)){
                        retorno++;
                        area.append(retorno+" arquivo(s) de "+cont+" copiado(s)\n");
                                                
                        new ProgressBar().executaProgresso(progresso, retorno, cont);              
                    }
                    
                    
                }   
           }
               catch (IOException e) {
                   e.printStackTrace();
               }

Sim, antes de executar o arquivo, eu leio quantas linhas tem e incremento esse cont.

Veja o código completo do botão.

private void btnCopia1ActionPerformed(java.awt.event.ActionEvent evt) {                                          

  
    String comando = "C:\\arquivoBat1.bat";
    String str; 
    int cont = 0;
        try {
            
         BufferedReader in = new BufferedReader(new FileReader(comando));
         
         while ((str=in.readLine())!= null) {
                if(str.contains("copy")){
                    cont++;
                }                
            }
            in.close();
            
            
            
         Process p = Runtime.getRuntime().exec("cmd /c "+comando);
         
         BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
         
         String s;
         
         float retorno = 0;
         
           try {
                
                while((s =result.readLine())!= null)
                {
                    
                    System.out.println(s); 
                    if("1 arquivo(s) copiado(s)".equals(s)){
                        retorno++;
                        area.append(retorno+" arquivo(s) de "+cont+" copiado(s)\n");
                                                
                        new ProgressBar().executaProgresso(progresso, retorno, cont);              
                    }
                    
                    
                }   
           }
               catch (IOException e) {
                   e.printStackTrace();
               }
            try {
                p.waitFor();
                btnCopia2.setEnabled(true);
                btnCopia1.setEnabled(false);
                
            } catch (InterruptedException ex) {
                Logger.getLogger(ExecBatFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            } catch (IOException ex) {
                Logger.getLogger(ExecBatFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
        
         
   
    
}
T

Consegui fazer atualizar o JTextArea e a barra de progresso a medida que os arquivos são copiados, retirei o código que estava em btnCopia1ActionPerformed e coloquei em uma thread separada:

class Copia extends Thread {

    private JProgressBar barra;
    private JTextArea area;
        
    public Copia(JProgressBar barra, JTextArea area) {
        this.barra = barra;
        this.area = area;
    }
    
        
    @Override
    public void run() {
        
        String comando = "C:\\teste\\teste\\teste.bat";
        String str; 
        int cont = 0;
            try {            
            BufferedReader in = new BufferedReader(new FileReader(comando));
         
            while ((str=in.readLine())!= null) {
                    if(str.contains("copy")){
                        cont++;
                    }                
                }
                in.close();
            Process p = Runtime.getRuntime().exec("cmd /c "+comando);
            BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
         
            String s;
         
            float retorno = 0;
         
            try {
                
                while((s =result.readLine())!= null)
                {
                    
                    System.out.println(s); 
                    if("1 arquivo(s) copiado(s).".equals(s.trim())){
                        retorno++;
                        area.append(retorno+" arquivo(s) de "+cont+" copiado(s)\n");
                         new ProgressBar().executaProgresso(progresso, retorno, cont);
                                      
                    }
                                       
                }   
           }
               catch (IOException e) {
                   e.printStackTrace();
               }
            try {
                p.waitFor();
                
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            }
    }
}

E no btnCopia1ActionPerformed coloquei:

Copia copia = new Copia(progresso, area);
copia.start();

Tive de adicionar um trim no if abaixo, pois o texto de retorno estava voltando com espaços no começo do texto:

if("1 arquivo(s) copiado(s).".equals(s.trim())){
J

t_java, vou fazer mais alguns testes, mas a principio não funcionou não.
Ainda vou testar melhor pra ver se não estou esquecendo de nada.
O .bat executa, tudo certinho, agora a progressbar e o JTextArea não atualizam nem no final. =/

J

Na classe separada com Thread também não rolou. Nem mesmo no final não aparece o texto na JTextArea e nem a barra de progresso atualiza.

Criado 13 de outubro de 2011
Ultima resposta 14 de out. de 2011
Respostas 10
Participantes 2