JProgressBar在新线程JDialog中

时间:2012-06-26 13:42:39

标签: java multithreading swing concurrency jprogressbar

我想在新的JDialog中制作JProgressBar,女巫将与主逻辑分开。因此,只需创建新的JDialog并完成处理JDialog的进度,我就可以开始不确定的进步。但它让我很难实现这一点,因为在JDialog出现之后它不显示任何组件(包括JProgressBar),直到主线程(SwingUtilities)中的逻辑完成。

线程包括JDialog:

package gui.progress;

public class ProgressThread extends Thread {
    private ProgressBar progressBar = null;

    public ProgressThread() {
        super();
    }

    @Override
    public void run() {
        progressBar = new ProgressBar(null);
        progressBar.setVisible(true);
    }

    public void stopThread() {
        progressBar.dispose();
    }
}

JProgressBar切换方法:

private static ProgressThread progressThread = null;
...
public static void toggleProcessBar() {
    if(progressThread == null) {
        progressThread = new ProgressThread();
        progressThread.start();
    } else {
        progressThread.stopThread();
        progressThread = null;
    }
}

2 个答案:

答案 0 :(得分:8)

  

但它让我很难实现这一点,因为在JDialog出现之后它不显示任何组件(包括JProgressBar),直到主线程(SwingUtilities)中的逻辑完成。

您遇到Concurrency in Swing问题,Swing是单线程的,所有更新必须在EventDispatchThread完成,有两种方式

  • 易于使用Runnable#Thread,但输出到Swing GUI必须包含在invokeLater

  • 使用SwingWorker,关于SwingWorker的示例位于Oracles JProgressBarSwingWorker教程

编辑

此代码模拟违反EDT并正确解决SwingWorker的解决方法

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

public class TestProgressBar {

    private static void createAndShowUI() {
        JFrame frame = new JFrame("TestProgressBar");
        frame.getContentPane().add(new TestPBGui().getMainPanel());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowUI();
            }
        });
    }

    private TestProgressBar() {
    }
}

class TestPBGui {

    private JPanel mainPanel = new JPanel();

    public TestPBGui() {
        JButton yourAttempt = new JButton("Your attempt to show Progress Bar");
        JButton myAttempt = new JButton("My attempt to show Progress Bar");
        yourAttempt.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                yourAttemptActionPerformed();
            }
        });
        myAttempt.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                myAttemptActionPerformed();
            }
        });
        mainPanel.add(yourAttempt);
        mainPanel.add(myAttempt);
    }

    private void yourAttemptActionPerformed() {
        Window thisWin = SwingUtilities.getWindowAncestor(mainPanel);
        JDialog progressDialog = new JDialog(thisWin, "Uploading...");
        JPanel contentPane = new JPanel();
        contentPane.setPreferredSize(new Dimension(300, 100));
        JProgressBar bar = new JProgressBar(0, 100);
        bar.setIndeterminate(true);
        contentPane.add(bar);
        progressDialog.setContentPane(contentPane);
        progressDialog.pack();
        progressDialog.setLocationRelativeTo(null);
        Task task = new Task("Your attempt");
        task.execute();
        progressDialog.setVisible(true);
        while (!task.isDone()) {
        }
        progressDialog.dispose();
    }

    private void myAttemptActionPerformed() {
        Window thisWin = SwingUtilities.getWindowAncestor(mainPanel);
        final JDialog progressDialog = new JDialog(thisWin, "Uploading...");
        JPanel contentPane = new JPanel();
        contentPane.setPreferredSize(new Dimension(300, 100));
        final JProgressBar bar = new JProgressBar(0, 100);
        bar.setIndeterminate(true);
        contentPane.add(bar);
        progressDialog.setContentPane(contentPane);
        progressDialog.pack();
        progressDialog.setLocationRelativeTo(null);
        final Task task = new Task("My attempt");
        task.addPropertyChangeListener(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equalsIgnoreCase("progress")) {
                    int progress = task.getProgress();
                    if (progress == 0) {
                        bar.setIndeterminate(true);
                    } else {
                        bar.setIndeterminate(false);
                        bar.setValue(progress);
                        progressDialog.dispose();
                    }
                }
            }
        });
        task.execute();
        progressDialog.setVisible(true);
    }

    public JPanel getMainPanel() {
        return mainPanel;
    }
}

class Task extends SwingWorker<Void, Void> {

    private static final long SLEEP_TIME = 4000;
    private String text;

    public Task(String text) {
        this.text = text;
    }

    @Override
    public Void doInBackground() {
        setProgress(0);
        try {
            Thread.sleep(SLEEP_TIME);// imitate a long-running task
        } catch (InterruptedException e) {
        }
        setProgress(100);
        return null;
    }

    @Override
    public void done() {
        System.out.println(text + " is done");
        Toolkit.getDefaultToolkit().beep();
    }
}

答案 1 :(得分:1)

在主线程中显示进度条(所有挥杆内容都在哪里),并在单独的线程上进行密集的后台工作。

UI将始终响应(因为您不阻止主线程),并且您可以在长时间运行的任务完成时通知它。