I have a generic Java class for a simple progress indicator. It works fine if invoked directly (e.g. from main() or from a class constructor). But I can't get it to work when I create a simple menu and invoke it from an ActionListener associated with a menu item.
Here's the generic progress indicator class:
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
public class jpcProgressIndicator {
final int MAX = 100;
private JFrame frame = new JFrame("Progress Indicator");
// creates progress bar
final JProgressBar pb = new JProgressBar();
final JTextField tf = new JTextField();
public jpcProgressIndicator() {
pb.setMinimum(0);
pb.setMaximum(MAX);
pb.setStringPainted(true);
// add progress bar
frame.setLayout(new FlowLayout());
frame.getContentPane().add(pb);
// frame.getContentPane().add(tf);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setSize(300, 70);
frame.setLocationRelativeTo(null);
}
public void Update( int nValue) {
pb.setValue(nValue);
}
public void Show( boolean flag) {
if(flag == true) {
this.frame.setVisible(true);
this.pb.setVisible(true);
} else {
this.pb.setVisible(false);
}
}
public int getValue() {
return this.pb.getValue();
}
public void setTitle(String strTitle) {
this.frame.setTitle(strTitle);
}
public void Close() {
frame.dispose();
}
}
The test program from which I'm invoking this is:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import SurveySystem.Data.jpcProgressIndicator;
public class Main2 implements ActionListener {
final int MAX = 100;
jpcProgressIndicator pi;
JFrame frame;
JMenuBar mb;
JMenuItem myMenuItem;
Main2() {
// Process();
// create the basic frame window for a menu
frame=new JFrame("Survey System");
// Create a menu item
myMenuItem = new JMenuItem("Process");
// add an actionlistener for this menu item
myMenuItem.addActionListener(this);
// create a menu bar
mb=new JMenuBar();
// add menu item to menu bar
mb.add(myMenuItem);
// add the menu bar to the frame
frame.add(mb);
frame.setJMenuBar(mb);
// set frame size
frame.setSize(800,400);
// center the frame on the screen
frame.setLocationRelativeTo(null);
// make the frame visible
frame.setVisible(true);
}
public static void main(String[] args) {
new Main2();
}
private void Process() {
pi = new jpcProgressIndicator();
pi.setTitle("Progress of Growth & Persistency");
pi.Update(0); // initialize
pi.Show(true);
int nCounter = 0;
// for (int i = 0; i <= MAX; i++) {
while (nCounter < 100 ) {
// final int currentValue = i;
final int currentValue = nCounter;
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
pi.Update(currentValue);
}
});
java.lang.Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Error: " + e.getMessage());
}
nCounter++;
}
pi.Close();
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == myMenuItem)
Process();
}
}
The test method Process loops and updates the progress bar. I have commented out an invocation that, if uncommented, shows that all the code is working. But if I invoke it from the menu item, the frame appears but not the progress bar.
Anyone know what I'm doing wrong?
actionPerformed is actually executed by EDT, so all invokeLater calls are queued and called after the pi.Close so that you can't see the progressbar update.
Here is how I modified your Process method to "take the counter out of EDT":
private void Process() {
jpcProgressIndicator pi = new jpcProgressIndicator();
pi.setTitle("Progress of Growth & Persistency");
pi.Update(0); // initialize
pi.Show(true);
Thread t = new Thread(new Runnable(){
public void run() {
int nCounter = 0;
// for (int i = 0; i <= MAX; i++) {
while (nCounter < 100 ) {
// final int currentValue = i;
final int currentValue = nCounter;
try {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
pi.Update(currentValue);
}
});
java.lang.Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("Error: " + e.getMessage());
}
nCounter++;
}
pi.Close();
}
});
t.start();
}