开发者

JProgressBar not displaying correctly from ActionEvent

In the below code the JProgressBar displays correctly when the doSomething() is called from within main() but not when called as a result of an ActionEvent - the interface seems to freeze. What is the problem?

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

Thanks


Everything you do with Swing components should be done on the event dispatch thread (EDT) (i.e. the thread used by Swing to call your events). You should launch threads to perform lengthy background operations.

In your code, you do the reverse : you try showing the dialog in another thread, and perform the long operation in the EDT.

Here's the fixed code :

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

You should read this tutorial, and learn to use SwingWorker for background tasks.


The problem here is that you are doing dlg.show() on the new thread that blocks that thread and you have Thread.sleep() on your main thread so pretty much everything is blocked. Besides JDialog.show() and hide() are deprecated and you might want to be using setVisible(true/false), but that was not causing any issue in your case. If you are trying to display a dialog with a progress bar for some time and then close it, here's the fixed code. There is a second thread now that takes care of hiding the dialog after some time leaving the main thread to do it's thing.

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜