JProgressBar无法从ActionEvent正确显示

时间:2011-02-27 15:51:29

标签: java multithreading swing jprogressbar

在下面的代码中,JProgressBardoSomething()内调用时main()正确显示,但ActionEvent调用后却无法正常显示 - 界面似乎冻结。有什么问题?

import java.awt.BorderLayout; 

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.Vector;


public class ThreadedDialog  extends JFrame implements ActionListener{                
    private JDialog dlg;
    private JButton button;

    private void buildInterface(){
        button = new JButton("do stuff;");
        button.addActionListener(this);
        this.getContentPane().setLayout(new BorderLayout()); 
        this.getContentPane().add(BorderLayout.CENTER, button); 


        dlg = new JDialog(this, "Progress Dialog", true); 
        JProgressBar dpb = new JProgressBar(0, 500); 
        dlg.getContentPane().setLayout(new BorderLayout()); 
        dlg.getContentPane().add(BorderLayout.CENTER, dpb); 
        dlg.getContentPane().add(BorderLayout.NORTH, new JLabel("Progress..."));         
        dlg.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); 
        dlg.setSize(300, 75); 
        dlg.setLocationRelativeTo(this);
        dpb.setIndeterminate(true);        
    }

    public void doSomething(){
        Thread t = new Thread(new Runnable(){ 
            public void run() { 
                dlg.show(); 
            } 
        });                          
        t.start();     
        try { 
            for (int i=0; i<100; i++){
                System.out.println("wtf is going on here?");
                Thread.sleep(5000);
            }
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        }
        dlg.hide();         
    }

    public static void main(String[] args) { 
        ThreadedDialog me = new ThreadedDialog();

        me.buildInterface();        
        me.pack();
        me.setVisible(true);
        me.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        //me.doSomething();
    }

    public void actionPerformed(ActionEvent event) {
        doSomething();
    }
} 

由于

2 个答案:

答案 0 :(得分:2)

使用Swing组件执行的所有操作都应该在事件派发线程(EDT)上完成(即Swing用来调用事件的线程)。您应该启动线程以执行冗长的后台操作。

在你的代码中,你会反过来:你尝试在另一个线程中显示对话框,并在EDT中执行长操作。

这是固定代码:

package fr.free.jnizet.stackoverflow;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;


public class ThreadedDialog  extends JFrame implements ActionListener{
    private JDialog dlg;
    private JButton button;

    private void buildInterface(){
        button = new JButton("do stuff;");
        button.addActionListener(this);
        this.getContentPane().setLayout(new BorderLayout());
        this.getContentPane().add(BorderLayout.CENTER, button);


        dlg = new JDialog(this, "Progress Dialog", true);
        JProgressBar dpb = new JProgressBar(0, 500);
        dlg.getContentPane().setLayout(new BorderLayout());
        dlg.getContentPane().add(BorderLayout.CENTER, dpb);
        dlg.getContentPane().add(BorderLayout.NORTH, new JLabel("Progress..."));
        dlg.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        dlg.setSize(300, 75);
        dlg.setLocationRelativeTo(this);
        dpb.setIndeterminate(true);
    }

    public void doSomething(){
        // create a thread for the background task
        Thread t = new Thread(new Runnable(){
            public void run() {
                try {
                    for (int i=0; i<100; i++){
                        System.out.println("wtf is going on here?");
                        Thread.sleep(5000);
                    }
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // when the background task is finished, hide the dialog in the EDT.
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        dlg.setVisible(false);
                    }

                });
            }
        });
        t.start();

        // show the dialog in the EDT
        dlg.setVisible(true);
    }

    public static void main(String[] args) {
        // create the GUI in the EDT
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                ThreadedDialog me = new ThreadedDialog();

                me.buildInterface();
                me.pack();
                me.setVisible(true);
                me.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
        });

    }

    public void actionPerformed(ActionEvent event) {
        doSomething();
    }
}

您应该阅读this tutorial,并学会使用SwingWorker进行后台任务。

答案 1 :(得分:1)

这里的问题是你在阻塞该线程的新线程上执行dlg.show()并且你的主线程上有Thread.sleep()所以几乎所有东西都被阻止了。除JDialog.show()hide()之外,我们不推荐您使用setVisible(true/false),但这并不会导致任何问题。如果您尝试显示带有进度条的对话框一段时间然后关闭它,则这是固定代码。现在有一个第二个线程负责在离开主线程完成它之后隐藏对话框。

import java.awt.BorderLayout;

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

public class ThreadedDialog extends JFrame implements ActionListener {
    private JDialog dlg;
    private JButton button;

    private void buildInterface() {
        button = new JButton("do stuff;");
        button.addActionListener(this);
        this.getContentPane().setLayout(new BorderLayout());
        this.getContentPane().add(BorderLayout.CENTER, button);

        dlg = new JDialog(this, "Progress Dialog", true);
        JProgressBar dpb = new JProgressBar(0, 500);
        dlg.getContentPane().setLayout(new BorderLayout());
        dlg.getContentPane().add(BorderLayout.CENTER, dpb);
        dlg.getContentPane().add(BorderLayout.NORTH, new JLabel("Progress..."));
        dlg.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        dlg.setSize(300, 75);
        dlg.setLocationRelativeTo(this);
        dpb.setIndeterminate(true);

    }

    public void doSomething() {
        Thread t1 = new Thread(new Runnable() {
            public void run() {
                dlg.setVisible(true);

            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("wtf is going on here?");
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                dlg.setVisible(false);

            }
        });
        t1.start();
        t2.start();

    }

    public static void main(String[] args) {
        ThreadedDialog me = new ThreadedDialog();

        me.buildInterface();
        me.pack();
        me.setVisible(true);
        me.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // me.doSomething();
    }

    public void actionPerformed(ActionEvent event) {
        doSomething();
    }
}