我想在关闭主框架时显示进度条窗口。但是,进度条窗口将不显示任何内容,我不知道它。这是代码。
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class MainFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
MainFrame mainFrame = new MainFrame();
mainFrame.createUI();
}
});
}
public void createUI(){
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel(new BorderLayout());
JButton button = new JButton("Close");
button.setBorder(new EmptyBorder(20, 20, 20, 20));
button.addActionListener(new ButtonListener());
mainPanel.add(button,BorderLayout.CENTER);
frame.add(mainPanel,BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
class ButtonListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
FeedbackBox feedbackBox = new FeedbackBox();
feedbackBox.createUI();
feedbackBox.increment(0, 100);
try {
feedbackBox.getThread().join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
feedbackBox.closeBox();
}
}
}
进度条窗口是:
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
public class FeedbackBox {
private JFrame frame;
private JProgressBar progressBar;
Thread thread;
public void createUI(){
frame = new JFrame("Reminder");
MainPanel mainPanel = new MainPanel();
frame.add(mainPanel,BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
public JProgressBar getProgressBar(){
return progressBar;
}
public void closeBox(){
frame.dispose();
}
public void increment(final int minimum,final int maximum){
thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = minimum; i <= maximum; i++) {
getProgressBar().setValue(i);
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
thread.start();
}
public Thread getThread(){
return thread;
}
@SuppressWarnings("serial")
class MainPanel extends JPanel{
public MainPanel(){
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
progressBar = new JProgressBar();
progressBar.setStringPainted(true);
progressBar.setIndeterminate(true);
progressBar.setBackground(Color.white);
progressBar.setForeground(Color.blue);
JPanel topPanel = new JPanel();
topPanel.add(progressBar);
JLabel label = new JLabel("It is closing. ");
label.setForeground(Color.blue);
label.setBackground(Color.WHITE);
JPanel bottomPanel = new JPanel();
bottomPanel.add(label);
add(topPanel);
add(Box.createVerticalStrut(10));
add(bottomPanel);
}
}
}
如果我删除
try {
feedbackBox.getThread().join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
feedbackBox.closeBox();
然后一切都会好的。为什么?感谢您的帮助。
基于@Hovercraft Full Of Eels的帮助。我修改了我的代码。但是,有线的东西仍在这里。除非我手动关闭进度条窗口,否则不会调用void propertyChange。
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class MainFrame {
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
MainFrame mainFrame = new MainFrame();
mainFrame.createUI();
}
});
}
public void createUI(){
frame = new JFrame();
JPanel mainPanel = new JPanel(new BorderLayout());
JButton button = new JButton("Close");
button.addActionListener(new ButtonListener());
button.setBorder(new EmptyBorder(20, 20, 20, 20));
mainPanel.add(button,BorderLayout.CENTER);
frame.add(mainPanel,BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
class ButtonListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
FeedbackBox feedbackBox = new FeedbackBox(frame,0,100,"It is closing");
feedbackBox.displayDialog();
}
}
}
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
public class FeedbackBox {
private JDialog dialog;
private MyWorker myWorker;
private JProgressBar progressBar = new JProgressBar();
public FeedbackBox(Window win,int minimum,int maximum,String title){
myWorker = new MyWorker(minimum, maximum);
MainPanel mainPanel = new MainPanel(minimum,maximum);
myWorker.addPropertyChangeListener(new MyWorkerListener());
dialog = new JDialog(win,title,ModalityType.APPLICATION_MODAL);
dialog.add(mainPanel,BorderLayout.CENTER);
dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
dialog.setResizable(false);
dialog.setLocationRelativeTo(win);
dialog.pack();
}
public void displayDialog(){
dialog.setVisible(true);
myWorker.execute();
}
public void closeBox(){
dialog.dispose();
}
@SuppressWarnings("serial")
class MainPanel extends JPanel{
public MainPanel(int minimum,int maximum){
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
progressBar.setMinimum(minimum);
progressBar.setMaximum(maximum);
progressBar.setStringPainted(true);
progressBar.setIndeterminate(true);
progressBar.setBackground(Color.white);
progressBar.setForeground(Color.blue);
JPanel topPanel = new JPanel();
topPanel.add(progressBar);
JLabel label = new JLabel("It is closing.");
label.setForeground(Color.blue);
label.setBackground(Color.WHITE);
JPanel bottomPanel = new JPanel();
bottomPanel.add(label);
add(topPanel);
add(Box.createVerticalStrut(10));
add(bottomPanel);
}
}
class MyWorkerListener implements PropertyChangeListener{
@Override
public void propertyChange(PropertyChangeEvent evt) {
// TODO Auto-generated method stub
if (evt.getPropertyName().equals(MyWorker.VALUE)) {
System.out.println("myWorker.getValue()" + myWorker.getValue());
progressBar.setValue(myWorker.getValue());
}
if (evt.getNewValue() == SwingWorker.StateValue.DONE && dialog != null) {
closeBox();
}
}
}
}
class MyWorker extends SwingWorker<Void, Void>{
public static final String VALUE = "value";
private int value;
private int minimum;
private int maximum;
public MyWorker(int minimum,int maximum){
this.minimum = minimum;
this.maximum = maximum;
value = minimum;
}
@Override
protected Void doInBackground() throws Exception {
// TODO Auto-generated method stub
for (int i = minimum; i <= maximum; i++) {
setValue(i);
Thread.sleep(30);
}
return null;
}
public void setValue(int i){
int oldValue = this.value;
int newValue = i;
this.value = i;
firePropertyChange(VALUE, oldValue, newValue);
}
public int getValue(){
return value;
}
}
答案 0 :(得分:4)
通过将您的线程与Swing事件线程连接,您可以使线程成为非后台线程,从而占用Swing事件线程,阻止它完成其工作 - 绘制GUI并与用户交互,这将冻结您的对话窗口(顺便说一句,它应该是JDialog而不是单独的JFrame)。解决方案:不加入线程。此外,您的后台线程不应该像当前那样更改Swing组件的状态。最好使用SwingWorker来让你在后台线程上保持事件线程和背景事物的Swing。
有关血腥的详细信息,请阅读Lesson: Concurrency in Swing - Oracle Documentation
例如:
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
@SuppressWarnings("serial")
public class ClosingDialogPanel {
private JPanel mainPanel = new JPanel();
private JProgressBar progressBar = new JProgressBar();
private JDialog dialog;
private MyWorker myWorker;
public ClosingDialogPanel(Window win, int minimum, int maximum, String title) {
myWorker = new MyWorker(minimum, maximum);
progressBar.setMinimum(minimum);
progressBar.setMaximum(maximum);
myWorker.addPropertyChangeListener(new WorkerListener());
progressBar.setStringPainted(true);
mainPanel.add(progressBar);
dialog = new JDialog(win, title, ModalityType.APPLICATION_MODAL);
dialog.add(mainPanel);
dialog.pack();
dialog.setLocationRelativeTo(win);
}
public void displayDialog() {
myWorker.execute();
dialog.setVisible(true);
}
private class WorkerListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (MyWorker.VALUE.equals(evt.getPropertyName())) {
progressBar.setValue(myWorker.getValue());
}
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
if (dialog != null && dialog.isVisible()) {
dialog.dispose();
}
try {
myWorker.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
private static void createAndShowGui() {
final JFrame frame = new JFrame("Closing Frame");
JButton closeBtn = new JButton(new AbstractAction("Close") {
@Override
public void actionPerformed(ActionEvent e) {
final ClosingDialogPanel closingDlg = new ClosingDialogPanel(frame, 0,
200, "Closing");
closingDlg.displayDialog();
}
});
JPanel panel = new JPanel();
panel.add(closeBtn);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MyWorker extends SwingWorker<Void, Void> {
public static final String VALUE = "value";
private int value;
private int minimum;
private int maximum;
public MyWorker(int minimum, int maximum) {
this.minimum = minimum;
this.maximum = maximum;
value = minimum;
}
@Override
protected Void doInBackground() throws Exception {
for (int i = minimum; i <= maximum; i++) {
setValue(i);
Thread.sleep(30);
}
return null;
}
private void setValue(int i) {
int oldValue = this.value;
int newValue = i;
this.value = i;
firePropertyChange(VALUE, oldValue, newValue);
}
public int getValue() {
return value;
}
}