Reputation: 512
Here is a little a example:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
int x = 0;
while (jProgressBar1.getValue() < 100) {
try {
Thread.sleep(50);
x++;
jProgressBar1.setValue(x);
jProgressBar1.repaint();
} catch (InterruptedException ex) {
Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(jProgressBar1.getValue());
}
}
System.out.println(jProgressBar1.getValue());
returns digits to IDE output, but jProgressBar1 doesn't draw this value. What's wrong with this code? Please help.
Upvotes: 1
Views: 17184
Reputation: 7042
The problem is that you're calling .repaint()
in the same thread you're doing your "work" (Thread.sleep). "repaint() does not invoke paint() directly. It schedules a call to an intermediate method, update(). Finally, update() calls paint()...". This means you're scheduling a bunch of repaint()
calls, but they aren't being processed. I would also bet that once the value does reach 100 the progress bar jumps to being full, which is because the main thread has ended and all of the repaint()
calls are finally being processed.
In order to make jProgressBars work, you have to have their repainting occur in a different thread than the one in which you are doing work (which notably should also be in a different thread - This is also true for most Swing updating). Try starting this Runnable in a new thread before you invoke your code:
public class ProgressBarPainter implements Runnable{
public JProgressBar jProgressBar1;
public void run(){
while(true){
try {
Thread.sleep(50);
jProgressBar1.repaint();
} catch (InterruptedException ex) {
break;
}
}
}
}
Example functioning code to use the above:
public class Frame extends JFrame {
private static final long serialVersionUID = 1L;
private JProgressBar bar;
public Frame(){
JPanel contentPanel = (JPanel) getContentPane();
JButton b = new JButton("Do Process");
b.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
ProgressBarPainter p = new ProgressBarPainter();
p.jProgressBar1 = bar; //Fill in with the bar you want painted
Thread t = new Thread(p);
t.start();
Worker w = new Worker();
w.jProgressBar1 = bar;
Thread t2 = new Thread(w);
t2.start();
}
});
contentPanel.add(b, BorderLayout.SOUTH);
bar = new JProgressBar();
contentPanel.add(bar, BorderLayout.CENTER);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new Frame();
}
}
class Worker implements Runnable{
public JProgressBar jProgressBar1;
public void run(){
int x = 0;
while(jProgressBar1.getValue() != jProgressBar1.getMaximum()){
try {
//Do some work
Thread.sleep(50);
//Update bar
jProgressBar1.setValue(x++);
} catch (InterruptedException ex) {
break;
}
}
}
}
class ProgressBarPainter implements Runnable{
public JProgressBar jProgressBar1;
public void run(){
while(true){
try {
Thread.sleep(50);
jProgressBar1.repaint();
} catch (InterruptedException ex) {
break;
}
}
}
}
Upvotes: -1
Reputation: 11327
Never use Thread.sleep() in Swing thread. Use javax.swing.Timer instead.
Example:
private void jButton1ActionPerformed(ActionEvent evt) {
final Timer t = new Timer(50, new ActionListener() {
public void actionPerformed(ActionEvent e) {
jProgressBar1.setValue(jProgressBar1.getValue() + 1);
if (jProgressBar1.getValue() == 100) {
((Timer) e.getSource()).stop();
}
}
});
t.start();
}
Upvotes: 3