在下面的代码中,JProgressBar
在doSomething()
内调用时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();
}
}
由于
答案 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();
}
}