------------------siwuxie095
工程名:SwingUIThreadSafeTest
包名:com.siwuxie095.swinguithread
类名:MyFrame.java
工程结构目录如下:
代码:
package com.siwuxie095.swinguithread;
import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent;
import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.EmptyBorder;
import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
//MyFrame 直接继承自 JFrame public class MyFrame extends JFrame {
private JPanel contentPane;
/** * Launch the application. */
public staticvoid main(String[] args) {
EventQueue.invokeLater(new Runnable() { publicvoid run() { try { MyFrame frame = new MyFrame(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } });
}
/** * Create the frame. */ public MyFrame() {
try { UIManager.setLookAndFeel(new WindowsLookAndFeel()); } catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); }
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setLayout(new BorderLayout(0, 0)); setContentPane(contentPane);
JProgressBar progressBar = new JProgressBar(); contentPane.add(progressBar, BorderLayout.NORTH);
JButton btnRun = new JButton("Run");
//为按钮 Run 添加 mouseClicked 事件 btnRun.addMouseListener(new MouseAdapter() { @Override publicvoid mouseClicked(MouseEvent e) { /********************************************************* * 非安全操作(1) * * 点击 Run 按钮后,该按钮不会弹起,进度条也不会增加,即界面卡死,没有任何反应 * 直到 10 秒后,Run 按钮弹起,进度条直接跳到满格,中间的所有过程都没有被展示 * * 出现这种情况的原因:当为鼠标添加的事件触发后,调用 mouseClicked()方法, * 该方法也是被当前的UI线程所执行的,一旦UI线程中出现了类似 sleep(1000) 这样的阻塞方法, * 将造成UI线程一直在阻塞的地方等待,而不会执行任何界面刷新的工作,这就导致了界面卡死的现象 * * 如果要编写一个响应良好的界面,不能在UI线程中执行非常耗时的操作 * 如:等待、UI的读写、网络的读写 * * 如果一定要执行等待、或每隔多长时间执行一个特殊的动作,可以使用 Swing 的 Timer 进行操作 * 如果需要读取大量的网络数据,或读写本地文件,可以创建一个新的线程 SwingWorker ********************************************************* */
// //(1)只需点击一次按钮 // for (int i = 1; i <= 10; i++) { // try { // //1 秒进度条增加一格 // //有异常抛出,用 try catch 捕获 // Thread.sleep(1000); // progressBar.setValue(i*10); // } catch (InterruptedException e1) { // e1.printStackTrace(); // } // }
/********************************************************* * 安全操作(2) * * 在为界面中的元素添加的监听器(各种事件)触发所产生的回调方法 * 都是由 Swing 的事件派发线程(UI线程)来完成的 * * 在UI线程中可以非常安全操作任何元素的属性 * 如:让进度条根据自己的 value 加 10 ********************************************************* */
//(2)需要连续点击按钮 progressBar.setValue(progressBar.getValue()+10);
} });
btnRun.setFocusable(false); contentPane.add(btnRun, BorderLayout.SOUTH); }
} |
将窗体JFrame 的 LookAndFeel 设定为 Windows
在根面板 contentPane 的上方添加一个 JProgressBar,
下方添加一个JButton
将 JButton 的文本(text)改为 Run,并 Rename 为 btnRun,
将 focusable 属性设为 false
为 JButton 添加 mouseClicked 事件,当点击 Run 按钮时,进度条的增加
非安全操作:
运行程序:
点击 Run 按钮后,按钮不会弹起,进度条也不会增加,
即界面卡死。直到 10 秒后,Run 按钮才弹起,进度条
直接跳到满格
界面卡死的原因:
当为鼠标添加的事件触发后,调用 mouseClicked()方法,
该方法也是被当前的UI线程所执行的
一旦UI线程中出现类似 Thread.sleep(1000); 这样的阻塞方法,将
造成UI线程一直在阻塞处 Thread.sleep(1000);等待 ,而不会执行
任何界面刷新的工作,进而导致界面卡死
安全操作:
运行程序:
因界面中元素的监听器(各种事件)触发所产生的回调方法都是
由 Swing 的事件派发线程(UI线程)来完成的
「事件派发线程即Event Dispatch Thread,简称 EDT」
所以,如果要编写一个响应良好的界面,不能在UI线程中执行非常耗时的操作
如:等待、文件的读写、网络数据的读写
如果一定要执行等待、或每隔一定时间执行一个特殊的动作,可以
使用 Swing 的 Timer 进行操作
如果需要读取大量的网络数据,或读写本地文件,可以
使用Swing 的 SwingWorker 进行操作
【made by siwuxie095】