*DET:
*SwingUtitlies.invokeLater
Swing一般有三种类型的线程:
*Initial Thread (初始化线程):在许多Swing程序中,该线程主要目的是启动程序的图形用户界面(GUI)。创建UI的点,也就是程序开始将控制权转交给UI时的点。一旦GUI启动后,对于大多数事件驱动的桌面程序来说,初始化线程的工作就结束了。每个程序必须有一个main方法,这是程序的入口。该方法运行在初始化或启动线程上。初始化线程读取程序参数并初始化一些对象。
*EDT (UI事件调度线程): Swing程序只有一个EDT,该线程负责GUI组件的绘制和更新,通过调用程序的事件处理器来响应用户交互。所有事件处理都是在EDT上进行的,程序同UI组件和其基本数据模型的交互只允许在EDT上进行,所有运行在EDT上的任务应该尽快完成,以便UI能及时响应用户输入。
*Worker Thread (任务线程): Swing程序只有一个EDT,该线程负责GUI组件的绘制和更新,通过调用程序的事件处理器来响应用户交互。所有事件处理都是在EDT上进行的,程序同UI组件和其基本数据模型的交互只允许在EDT上进行,所有运行在EDT上的任务应该尽快完成,以便UI能及时响应用户输入。
两个规范:
*所有的界面相关更新,都应当在 EDT 中执行
*不要在 EDT 中执行耗时代码,耗时工作应当有一个单独的线程去处理(应该通过SwingWoker来处理)
====
*错误做法:直接在EDI里面进行耗时的处理,the result is JLabel不能及时显示正确内容
public class Test1 extends JFrame implementsActionListener {private JButton btn = new JButton("Start");private JLabel lab = newJLabel(){public voidpaint(Graphics g){super.paint(g);
System.out.println("paint");
}
};publicTest1() {
init();
}public static voidmain(String[] args) {newTest1();
}private voidinit() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
setLocationRelativeTo(null);
setLayout(newFlowLayout());
add(btn);
add(lab);
btn.addActionListener(this);
setVisible(true);
}public voidactionPerformed(ActionEvent e) {for(int i=0;i<10;i++) { //耗时代码在EDI里面执行,看到JLabel内容就是90了
lab.setValue(i*10);
}
}
}
*错误做法:直接在EDI里面进行耗时的处理,the result is JLabel不能及时显示正确内容;界面如死机般僵硬 2 秒之后才显示
public class Test1 extends JFrame implementsActionListener {private JButton btn = new JButton("Start");private JLabel lab = newJLabel(){public voidpaint(Graphics g){super.paint(g);
System.out.println("paint");
}
};publicTest1() {
init();
}public static voidmain(String[] args) {newTest1();
}private voidinit() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
setLocationRelativeTo(null);
setLayout(newFlowLayout());
add(btn);
add(lab);
btn.addActionListener(this);
setVisible(true);
}public voidactionPerformed(ActionEvent e) {for(int i=0;i<10;i++) { //耗时代码在EDI里面执行,看到JLabel内容就是90了
try{
Thread.sleep(200);
}catch(Exception e){
e.printStackTrace();
}
lab.setText("Text: "+i);
}
}
}
改进:不要在 EDT 中执行耗时代码,耗时工作应当有一个单独的线程去处理;
但是这个demo还没做到在EDI里面显示: Swing 的单线程规范
packageedu.utas.gui;importjava.awt.FlowLayout;importjava.awt.Graphics;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjavax.swing.JButton;importjavax.swing.JFrame;importjavax.swing.JLabel;importjavax.swing.SwingUtilities;public class Test1 extends JFrame implementsActionListener {private JButton btn = new JButton("Start");private JLabel lab = newJLabel(){public voidpaint(Graphics g){super.paint(g);
System.out.println("paint");
}
};
publicTest1() {
init();
}public static voidmain(String[] args) {newTest1();
}private voidinit() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
setLocationRelativeTo(null);
setLayout(newFlowLayout());
add(btn);
add(lab);
btn.addActionListener(this);
setVisible(true);
}public voidactionPerformed(ActionEvent e) {
Runnable runnable= newRunnable() {int i = 0;
@Overridepublic voidrun() {for (; i < 100; i++) {try{
Thread.sleep(200);
}catch(InterruptedException e) {
e.printStackTrace();
}
lab.setText("Text: "+i);
}
}
};newThread(runnable).start();
}
}
改进: 把显示放到EDI里面进行;使用SwingUtilities.invokeLater.
packageedu.utas.gui;importjava.awt.FlowLayout;importjava.awt.Graphics;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjavax.swing.JButton;importjavax.swing.JFrame;importjavax.swing.JLabel;importjavax.swing.SwingUtilities;public class Test1 extends JFrame implementsActionListener {private JButton btn = new JButton("Start");private JLabel lab = newJLabel(){public voidpaint(Graphics g){super.paint(g);
System.out.println("paint");
}
};publicTest1() {
init();
}public static voidmain(String[] args) {newTest1();
}private voidinit() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
setLocationRelativeTo(null);
setLayout(newFlowLayout());
add(btn);
add(lab);
btn.addActionListener(this);
setVisible(true);
}public voidactionPerformed(ActionEvent e) {
Runnable runnable= newRunnable() {int i = 0;
@Overridepublic voidrun() {for (; i < 100; i++) {try{
Thread.sleep(200);
}catch(InterruptedException e) {
e.printStackTrace();
}//Swing 的单线程规范; 要在 EDT 中执行界面更新操作//Swing 提供了一个强大的工具类:SwingUtilities它提供了好几个功能强大的方法,//这里,我们需要的是:invokeLater 这个方法//这个方法的作用是:把一个任务,排队到 EDT 的最后,等待执行,//其实 Swing 为了处理这种类似的问题,专门提供了一个功能强大的类:SwingWorker
SwingUtilities.invokeLater(newRunnable() {
@Overridepublic voidrun() {
lab.setText("text: "+i);
}
});
}
}
};newThread(runnable).start();
}
}
===
holder