从 ActionListener 调用时不显示 JProgressbar

JProgressbar doesn't display when invoked from an ActionListener

我有一个通用的 Java class 作为简单的进度指示器。如果直接调用(例如从 main() 或 class 构造函数),它工作正常。但是当我创建一个简单的菜单并从与菜单项关联的 ActionListener 调用它时,我无法让它工作。

这是通用进度指示器 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(); 
    }
}

我调用它的测试程序是:

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();      
    }
}

测试方法Process循环更新进度条。我已经注释掉了一个调用,如果未注释,则表明所有代码都在工作。但是,如果我从菜单项中调用它,则会出现框架但不会出现进度条。

有人知道我做错了什么吗?

actionPerformed实际上是由EDT执行的,所以所有的invokeLater调用都是在pi.Close之后排队调用的,所以你看不到进度条更新。

以下是我如何修改您的 Process 方法以“从 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();

}