【问题标题】:Swing ProgressMonitor not working摇摆进度监视器不工作
【发布时间】:2013-10-07 16:55:14
【问题描述】:

我正在尝试在 Java Swing 中学习 ProgressMonitor。 我创建了这个简单的测试代码 -

public class ProgressMonitorTest extends JFrame 
{
private JPanel contentPane;
private ProgressMonitor progressMonitor;
private JButton button;
private static ProgressMonitorTest frame;
private static boolean isFrameReady;

public JButton getButton()
{
    return button;
}

public ProgressMonitor getProgressMonitor()
{
    return progressMonitor;
}

/**
 * Launch the application.
 */
public static void main(String[] args) 
{
    EventQueue.invokeLater(new Runnable() 
    {
        public void run() 
        {
            try 
            {
                frame = new ProgressMonitorTest();
                frame.setVisible(true);
                isFrameReady = true;
            } 
            catch (Exception e) 
            {
                e.printStackTrace();
            }
        }
    });

    while(!isFrameReady)
    {
        //
    }

    frame.getButton().addActionListener(new ActionListener() 
    {   
        @Override
        public void actionPerformed(ActionEvent e) 
        {
            try
            {
                for(int i=0;i<=10;i++)
                {
                    final int percent = i;
                    SwingUtilities.invokeAndWait(new Runnable() 
                    {   
                        @Override
                        public void run()
                        {
                            frame.getProgressMonitor().setProgress(percent * 10);
                            frame.getProgressMonitor().setNote("Completed " + percent*10 + "%.");
                        }
                    });
                    try
                    {
                        Thread.sleep(1000);
                    }
                    catch(Exception ee)
                    {
                        //
                    }                           
                }
            }
            catch(Exception es)
            {
                //
            }
        }           
    });
}

/**
 * Create the frame.
 */
public ProgressMonitorTest() 
{
    isFrameReady = false;

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 450, 300);
    setTitle("Progress Monitor");

    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    contentPane.setLayout(new BorderLayout(0, 0));

    progressMonitor = new ProgressMonitor(frame, "Update in progress...", "", 0, 10);
    button = new JButton("Click Here");
    contentPane.add(button);

    setContentPane(contentPane);
}

}

关于这个的几个问题-

  1. 如果我删除 isFrameReady 检查,程序会在我分配按钮的动作侦听器的那一行显示 NullPointerException

  2. 如果我保持上述检查,则单击按钮不会执行任何操作。

  3. 保持上述检查,然后调试它,我让它等待一段时间,然后它到达动作侦听器所在的行。在这种情况下,它可以工作,但会立即退出,说它不能从事件处理线程调用invokeAndWait

我在这一切中缺少什么?有人能解释一下如何让它工作吗?

【问题讨论】:

    标签: java swing progressmonitor


    【解决方案1】:

    如果我删除 isFrameReady 检查,程序会显示 NullPointerException 在我分配按钮操作的行 听众。

    您使用isFrameReady 可确保您已成功创建frame。在您的main 中,您使用调用EventQueue.invokeLater(new Runnable(){}) 向事件调度线程(EDT)发布请求:删除检查isFrameReady,您将在主线程中调用frame.getButton(),但尚未创建frame通过 EDT 中的frame = new ProgressMonitorTest();,因此出现NullPointerException

    如果我保持上述检查,则单击该按钮不会执行任何操作。

    你现在应该明白了,上面的检查与按钮点击无关。该按钮没有执行任何操作,因为 GUI 因违反 swing 的单线程规则而被冻结。将actionPerformed 方法的递增for 循环放在另一个线程中,如下面的代码片段所示,并从那里执行它。你会看到它工作正常。

     new Thread(){
        public void run()
        {
           for(int i=0; i<10; i++)
            {
               //whatever you were doing.
            }
        }
       }.start(); 
    

    保持上面的检查然后调试这个,我让它等待 在它到达动作侦听器所在的行之前的一段时间。在 在这种情况下,它可以工作,但立即退出说它无法调用 从事件处理线程调用AndWait。

    SwingUtitlies.invokeAndWait() 阻塞当前线程并等待直到 EDT 完成执行分配给它的任务。由于 actionPerformed() 函数已经在 EDT 内部运行,因此从当前线程调用 SwingUtitlies.invokeAndWait():EDT 将阻塞当前线程:EDT,这是不允许的。在这种情况下不要使用invokeAndWait。你应该打电话给SwingUtilities.invokeLater()

    但是,在您了解 Swing 线程模型之前,我认为您不会得到任何东西。阅读 javadoc 和一些互联网资源。一定要拥有这本书 Filthy Rich Clients 并尝试本书提供的示例:您将在图形效果方面拥有比任何其他资源都提供的更丰富的知识。

    【讨论】:

    • 感谢您的详细解答和书籍建议。一个问题 - 不是我分配动作侦听器(应用程序线程)的地方,它在 EventQueue.invokeLater 和 EDT 不同线程之外?还是那不一样?
    • 我不会直接回答你的问题。通过调用system.out.println(Thread.currentThread()) 函数,您将了解您现在所在的线程。将此代码放入各种代码块中并运行。你会自己看,你会自己得到答案
    • 谢谢!我会这样做的!
    • 我尝试将我的 actionPerformed 逻辑放在一个新的 Thread() 中并且它起作用了。现在我不明白为什么从新线程调用它有效,以及为什么从主应用程序线程调用它。我也无法在任何地方找到答案。你能解释一下吗?
    • 我已经在我的回答中说过了。当您在 actionPerformed() 函数中从 EDT 执行任务时,您的 GUI 会冻结。这就是为什么我们需要在另一个线程中执行 for 循环。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 2010-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多