Como puedo hacer un ProgressBar de forma correcta?

Que tal comunidad, tengo una duda y quisiera saber si alguien puede apoyarme al respecto. Les platico, estoy haciendo una aplicación en swing y cada vez que se ejecute un proceso a través de un botonazo se debe mostrar una barra de progreso, la cual si se muestra pero pues no mas no se ve el avance. Mi código resumido es el siguiente:

Mi form:

public class MainFrame extends javax.swing.JFrame {

    private JProgressBar pb = null;
    public Timer timer = null;
        private final JFrame frame = new JFrame("Espere un momento");

        public MainFrame() {
        initComponents();
                       
                JPanel panelPB = new JPanel();
                panelPB.setLayout(new BorderLayout());
                panelPB.add(pb);
                panelPB.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

                frame.setContentPane(panelPB);
                frame.pack();
       
                btnRespuesta.addActionListener(new java.awt.event.ActionListener() {
                        public void actionPerformed(java.awt.event.ActionEvent evt) {
                                btnRespuestaActionPerformed(evt);
                        }
                });

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        pack();
        }

    private void btnRespuestaActionPerformed(java.awt.event.ActionEvent evt) {
                response.responseFile(timer, pb);
                frame.setVisible(true);
    }
}

El Bussines:

public class ResponseFile {

        public void responseFile(Timer timer, JProgressBar pb){
                try {
                        //Create a timer.
                        timer = new Timer(1000, new ActionListener() {
                        public void actionPerformed(ActionEvent evt) {
                        /**
                        * Originalmente aqui esta el if, es decir:
                        * if (i == 20){ Toolkit.getDefaultToolkit().beep(); timer.stop(); pb.setValue(0); }
                        * i = i + 1; pb.setValue(i);
                        * pero me manda un error de tipo:
                        * Cannot refer to a non-final variable pb inside an inner class defined in a different method
                        **/

                        }
                        });

                timer.start();         
                for (int i = 0; i <= 20; i++) {
                        if (i == 20){
                                Toolkit.getDefaultToolkit().beep();
                                timer.stop();
                                pb.setValue(0);
                        }
                        i = i + 1;
                        pb.setValue(i);                
                }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
}

Como lo dije, no puse todo el código y espero no haber omitido nada importante. ¿Debo cambiar mi código para que funcione mi progress bar o que me recomiendan hacer? Porque así como lo tengo si se muestra pero nunca se ve el avance de la barra, agradezco su tiempo y su ayuda. Saludos.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de AlexSnake

Aun no

Habia publicado una solucion, pero no es correcta.

Imagen de ezamudio

EDT

Seguramente tienes la misma bronca de todo mundo... esa tarea larga que vas a realizar, que es la razón por la que vas a mostrar una barra de progreso, la debes realizar fuera del EDT. El EDT es el Event Dispatch Thread, que es el hilo dedicado a manejar todos los eventos de Swing.

Cuando el usuario oprime un botón en tu GUI, desde el EDT se invoca el método del botón que a su vez invocará los actionPerformed de los ActionListeners del mismo. Si ahí realizas la tarea larga, estás acaparando el EDT y por lo tanto la GUI no se actualiza.

Lo que necesitas es realizar tu tarea en un hilo separado, para liberar el EDT, y de vez en cuando el hilo de tu tarea (denominado worker thread) debe actualizar la barra de progreso.

Si estás usando Java, aprovecha la clase SwingWorker.

Imagen de AlexSnake

Oks

Gracias ezamudio, si suponia que tenia que ver algo con el actionPerformed pero no sabia que se fuera a complicar tanto, pero bueno a darle... revisare la clase SwingWorker y vere que puedo hacer. Saludos.

Imagen de ezamudio

Ejemplo

Lo hago en Groovy porque me da muuuuucha hueva estar escribiendo código Java para Swing....

Esto es lo que estás haciendo:

import javax.swing.*
import java.awt.event.*
import java.awt.*

def vent=new JFrame("Ejemplo de ProgressBar")
def box=Box.createVerticalBox()
box.add(new JLabel("Barra de Progreso"))
def pb=new JProgressBar(0, 1)
box.add(pb)
def boton=new JButton("Comenzar")
box.add(boton)
vent.contentPane.add(box)
vent.setSize(200, 100)
vent.visible=true
boton.addActionListener({
  10.times {
    println "Jeteando un segundo"
    Thread.sleep(1000)
    pb.value=it
  }
  println "Listo"
} as ActionListener)

(en Groovy es preferible que en vez de crear clases anónimas para implementar interfaces de un sólo método, pases mejor un closure y le hagas cast a la interfaz, resulta en lo mismo).

Ese código que imprime 10 veces "jeteando un segundo" corre en el EDT, por lo tanto nunca se ve que se actualice la barra de progreso, simplemente se queda pasmada la GUI 10 segundos y al final la barra aparece completamente llena.

Para que funcione como quieres, hay que hacer esto (en Groovy habría incluso maneras más sencillas pero tú lo vas a hacer en Java así que usemos el SwingWorker):

//Metemos toda la chamba en un SwingWorker
class Trabajador extends SwingWorker<Boolean, Integer> {

  Boolean doInBackground() {
    10.times {
      println "Jeteando un segundo"
      Thread.sleep(1000)
      progress=it*10
    }
    progress=100
    println "Listo"
    true
  }

}

//Y ahora el ActionListener queda así
boton.addActionListener({
  def t=new Trabajador()
  t.addPropertyChangeListener({ evento->
    if ("progress" == evento.propertyName) {
      pb.setValue(evento.newValue)
    }
  } as PropertyChangeListener)
  t.execute()
} as ActionListener)

Parece mucho relajo, pero realmente no lo es: Ahora el ActionListener lo que hace cuando oprimes el botón, es crear un Trabajador y agregarle un PropertyChangeListener, que escucha cuando alguna propiedad cambia (SwingWorker notifica de cambios en sus propiedades progress y state). Ese listener lo único que hace es que cuando cambia la propiedad progress del worker, actualiza la barra de progreso.

Las ventajas de todo este relajo:
- Bajo acoplamiento, porque ese código que hace la tarea tardada lo puedes tener en un componente separado (yo lo puse por simplicidad dentro del mismo SwingWorker, pero el SwingWorker podría ser un simple envoltorio para invocar esa tarea).
- La sincronización entre el hilo trabajador y el EDT lo hace Swing, tú no te tienes que preocupar por sincronizar nada; el método doInBackground se ejecutará en el hilo trabajador, pero los PropertyChangeListeners son invocados desde el EDT.
- Algunas invocaciones a los PropertyChangeListeners pueden ser ignoradas por performance. De este modo si cambias la propiedad progress del worker 100 veces, puede que solamente invoquen los listeners 10 veces, para tampoco atascar el EDT.

Imagen de AlexSnake

Entendido

No pues, muchas gracias ezamudio la neta me sacaste del bache en el que estaba ataskado, mas adelante mostrare la forma en que lo implemente pero claro con java, ademas con tu ejemplo me despierta mas el gusto por aprender Groovy, pero antes tengo que dominar mejor java.

Imagen de Nopalin

Tambien puedes echarle un

Tambien puedes echarle un vistazo a la libreria spin,

Sobres

Imagen de AlexSnake

pBar con Java

Aun que realmente la solución que implemente es realmente similar o casi igual a lo que ezamudio publico, pues la pongo con la finalidad de que le pueda servir a alguien mas.

En el Frame:

ResponseFile response = new ResponseFile(){
          @Override
          protected void done(){
                                button.setEnabled(true);
                                label.setText("Proceso completado.");
                }
        };
        response.addPropertyChangeListener(new PropertyChangeListener(){
                        public void propertyChange(PropertyChangeEvent event) {
                                if ("progress".equals(event.getPropertyName())) {
                                        pb.setValue( (Integer)event.getNewValue() );
                                }
                        }
        });
        response.execute();

En la clase de negocio:

public class ResponseFile extends SwingWorker<String, Void>{
        @Override
        protected String doInBackground() throws Exception {
               
                for (int i = 0; i <= 20; i++) {
                        setProgress((i+1) * 100 / 20);
                        Thread.sleep(500);
                }
                return "";

        }
       
    @Override
    protected void done() {
        setProgress(100);
        Toolkit.getDefaultToolkit().beep();
    }
}

Saludos.

@Nopalin ya stas le echare un vistaso. Saludos

Imagen de Rafael Carrillo

no se si me puedan ayudar con una progress bar

estoy intentando cambiar el relleno de una barra de progreso , sin embargo aunque cambio la propiedad Foreground a un color al momento de ejecutarlo siempre aparece el mismo, seleccione el que seleccione siempre pone un naranja

Mostraría el código pero no lo tengo a la mano ahora

Re: color de JProgressBar

 

Dependiendo del Look And Feel que esté cargado, este tomará en cuenta los colores que se pongan o lo hará parcialmente o no lo hará.

Considera el siguiente código:

LookAndFeelInfo[] lookAndFeels = UIManager.getInstalledLookAndFeels();
for (LookAndFeelInfo info : lookAndFeels) {
    UIManager.setLookAndFeel(info.getClassName());
    JProgressBar progressBar = new JProgressBar(1, 100);
    progressBar.setValue(50);
    progressBar.setStringPainted(true);
    progressBar.setBackground(Color.WHITE);
    progressBar.setForeground(Color.GREEN);
    JOptionPane.showMessageDialog(null, progressBar, "JProgressBar: " + info.getName(), JOptionPane.PLAIN_MESSAGE);
}

Algunos ejemplos:

  • Metal

    UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel")

    Metal

  • Nimbus

    UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel")

    Nimbus

  • Windows Classic

    UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel")

    Windows Classic

  • CDE/Motif

    UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel")

    CDE/Motif

En NetBeans, cuando creas, por ejemplo, un JFrame Form, se agrega código en el método main para cargar el Look And Feel (Nimbus) antes de crear cualquier componente. P.ej.:

/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
 * For details see <a href="http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html" title="http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html">http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html</a>
 */

try {
    for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
        if ("Nimbus".equals(info.getName())) {
            javax.swing.UIManager.setLookAndFeel(info.getClassName());
            break;
        }
    }
} catch (ClassNotFoundException ex) {
    java.util.logging.Logger.getLogger(Checks.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
    java.util.logging.Logger.getLogger(Checks.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
    java.util.logging.Logger.getLogger(Checks.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
    java.util.logging.Logger.getLogger(Checks.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>

Quita el for y pon el Look And Feel deseado, pero si quieres utilizar Nimbus, puedes intentar esto.

~~~

Imagen de Rafael Carrillo

gracias

me fue de ayuda

De nada.