当你运行一个 Swing 的程序时,会自动创建三个线程。
  第一个就是主线程,负责执行你的 main 方法.

第二个叫 toolkit 线程,负责捕捉系统事件,比如键盘、鼠标移动等,虽然这个 toolkit 非常重要,但是你不会有任何代码在这个线程上执行,这个线程的作用是,把这些事件传递给第三个线程:EDT

那 EDT 是什么呢?

EDT 叫做事件指派线程(Event Dispatcher Thread)
这个线程十分重要,他负责接收来自 toolkit 线程的事件, 然后派发给对应的控件的监听器,然后对应控件的监听器中对应方法的代码就会执行了, 注意,Swing 有一个单线程规范,即:
所有的界面相关的更新,都应该在 EDT 上执行, 而耗时的后台运行,不应该在 EDT 上执行。

这个 EDT 是干什么的呢?它负责指派所有的 GUI 事件, 比如键盘按钮按下后,派发给对应控件的监听器, 比如鼠标点击后,派发给对应控件的监听器, 比如:绘制控件。 所以,我们一般又喜欢把 EDT 叫做 GUI 线程。

EDT 是一种排队的模式,就是各种事件会在其中排队等待,依次执行其实所有的绘制,在 Swing 内部处理时,全都包装成了 Paint 事件然后进入 EDT 排队, 而且 EDT 还会智能的合并多个连续的 Paint 事件,把它们包装成一个 Paint 事件。

下面阐述一个重要的规范:Swing 单线程规范: “所有的界面相关更新,都应当在 EDT 中执行”
这个规范非常重要,在你编写 Swing 程序的过程中,请一直牢记他。

现在,让我们先来设定一个小小的目标,然后我们去实现它,从中探讨和发现问题
就做一个按时间变化的进度条吧,很多新手在刚开始时,都对这个功能的实现表示纠结。
下面,我们先来写一段代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ProgressFrame extends JFrame implements ActionListener {  
  
    private JButton btn = new JButton("Start");  
    private JProgressBar bar = new JProgressBar(){  
        public void paint(Graphics g) {  
            super.paint(g);  
            System.out.println("paint");  
        }  
    };  
  
    public ProgressFrame() {  
        init();  
    }  
  
    private void init() {  
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
        setSize(300,200);  
        setLocationRelativeTo(null);  
        setLayout(new FlowLayout());  
        add(btn);  
        add(bar);  
        btn.addActionListener(this);  
        setVisible(true);  
    }  
  
    @Override  
    public void actionPerformed(ActionEvent e) {  
        for (int i = 0; i <= 10; i++) {  
            bar.setValue(i * 10);  
        }  
    }  
      
    public static void main(String[] args) {  
        new ProgressFrame();  
    }  
  
}  
我们的想法很简单,就是在点下按钮后,让进度条设值 11 次,达到动画效果, 但是你运行后,点下按钮时,发现几乎是瞬间,进度条就满了, “paint”也只打印了一次.

是不是没有延时太快了? 那让我们对 actionPerformed 方法做一点小小的修改:

@Override  
public void actionPerformed(ActionEvent e) {  
    for (int i = 0; i <= 10; i++) {  
        try {  
            Thread.sleep(200);  
        } catch (InterruptedException e1) {  
            e1.printStackTrace();  
        }  
        bar.setValue(i * 10);  
    }  
}  
你会发现,按下按钮后,界面如死机般僵硬 2 秒之后,依然是进度条直接满, “paint”也只打印了一次.

这是什么原因呢?
下面我们要再说一个在编写 Swing 程序中,应该遵守的规则:

“不要在 EDT 中执行耗时代码,耗时工作应当有一个单独的线程去处理”
  因为如果你让耗时代码占用了 EDT,那 EDT 中的那些绘制啊什么的任务都将没空执行, 这些事件被压到 EDT 的最后去排队,然后又被 EDT 合并成了一个 Paint 事件, 从而结果就是:Paint 只在最后不再 sleep 之后,执行了一次

也许有人会很奇怪,这个 actionPerformed 怎么就在 EDT 中执行了呢? 还记得我们说过的 EDT 的作用么?
它会接受 toolkit 线程传递来的系统事件, 然后传递给对应控件的对应监听器,执行对应的方法。
   所以其实,这个 actionPerformed ,是由 EDT 调用执行的, 其实 Swing 控件的大部分监听器的各种方法,都是在 EDT 上执行的, 所以,我们要避免在这些监听器的方法中执行耗时操作,否则界面就会卡死!
   那我们要如何修改才能实现这样的效果呢? 我们需要让这个耗时的工作,在 EDT 之外的线程执行才行:
再次修改 actionPerformed 方法:
@Override  
 public void actionPerformed(ActionEvent e) {  
     Runnable runnable = new Runnable() {  
           
         @Override  
         public void run() {  
             for (int i = 0; i <= 10; i++) {  
                 try {  
                     Thread.sleep(200);  
                 } catch (InterruptedException e1) {  
                     e1.printStackTrace();  
                 }  
                 bar.setValue(i * 10);  
             }  
         }  
     };  
     new Thread(runnable).start();  
 }  
   我们用了一个单独的线程来执行这段代码。现在让我们再次执行,终于,我们看到了我们期望中的效果,进度条慢慢增加
“paint”也打印了十一次,那我们的程序是否就 OK 了呢?

答案是否定的,因为我们在这样实现的同时,又破坏了 Swing 的单线程规范, 没有在 EDT 中执行界面更新操作,
bar.setValue(i * 10); 这句话,应该在 EDT 中执行。 那这里不就有个矛盾了么?在 EDT 中执行也不行,
不在 EDT 中执行也不行……

其实我们要的只是 bar.setValue(i * 10); 这一句话在 EDT 中执行而已, 而 Swing 提供了一个强大的工具类:SwingUtilities
它提供了好几个功能强大的方法,这里,我们需要的是:invokeLater 这个方法,
这个方法的作用是:把一个任务,排队到 EDT 的最后,等待执行, 我们现在再次修改 actionPerformed 方法:

@Override  
public void actionPerformed(ActionEvent e) {  
    Runnable runnable = new Runnable() {  
          
        int i = 0;  
          
        @Override  
        public void run() {  
            for (i = 0; i <= 10; i++) {  
                try {  
                    Thread.sleep(200);  
                } catch (InterruptedException e1) {  
                    e1.printStackTrace();  
                }  
                SwingUtilities.invokeLater(new Runnable() {  
                      
                    @Override  
                    public void run() {  
                        bar.setValue(i * 10);  
                    }  
                });  
                  
            }  
        }  
    };  
    new Thread(runnable).start();  
}  
再次执行,效果和上一次一样,也满足了规范,皆大欢喜。 其实 Swing 为了处理这种类似的问题,
专门提供了一个功能强大的类:SwingWorker 
关于这个 SwingWorker 我会在以后找时间进行详细的解释,今天先说这么多吧。 当然,其实我们的程序还有一个小小的瑕疵:
public static void main(String[] args) {  
    new ProgressFrame();  
}  
这里,new ProgressFrame(); 的过程,其实也包含了大量的界面刷新等等 我们不应该让这样的代码在主线程中执行,应该把它放到 EDT 中去: 这样修改一下:
public static void main(String[] args) {  
    SwingUtilities.invokeLater(new Runnable() {  
          
        @Override  
        public void run() {  
            new ProgressFrame();  
        }  
    });      
}  
  这就是关于 Swing 的最重要的第一课:两个规范 “所有的界面相关更新,都应当在 EDT 中执行” “不要在 EDT 中执行耗时代码,耗时工作应当有一个单独的线程去处理” 这两条规范,将会伴随你的 Swing 程序,直到永远

转载于:https://www.cnblogs.com/smileallen/archive/2013/04/16/3391542.html

Swing如何正确的处理界面中的线程(EDT)相关推荐

  1. java swing 图片切换_在一个界面中要实现图片切换,用java要肿么实现??

    通常可以设置某个固定的切换时间,之后显示固定的或者是随机的显示某张图片,举例: import java.awt.*; import java.awt.event.*; import javax.swi ...

  2. 转:Swing中的线程探究

    http://superzhouych.iteye.com/blog/564907 ---------------------------------------------------------- ...

  3. java面试题7 牛客:关于AWT和Swing说法正确的是?

    关于AWT和Swing说法正确的是? A Swing是AWT的子类 B AWT在不同操作系统中显示相同的风格 C AWT不支持事件类型,Swing支持事件模型 D Swing在不同的操作系统中显示相同 ...

  4. wordpress怎么修改html,WordPress后台编辑器HTML模式界面中添加修改删除按钮

    在WordPress编辑器HTML模式界面中添加 按钮一文中,我大致介绍了怎么在后台添加一些自定义的按钮,本文则更为详细全面的对wordpress后台编辑器HTML模式下的按钮自定义进行详解,以让开发 ...

  5. 移动端界面中的版式设计原理

    "我总觉得页面不太好看但是我又说不出来","我不懂设计,但是我就是觉得不协调","你觉得这好看?你的审美要加强啊"这些听着熟悉的话往往是产品 ...

  6. 软件界面中一些易混淆/易用错的界面文案,以及一些约定俗成的文案约定

    经常有小伙伴跟我撕到底一些常用同音的词语应该使用哪个的问题.于是我将一些常用的软件界面中用错的文案整理出来,为自己和其他开发者提供我 已经整理的结论 和 可以溯源的资料. 本文内容 词语 撤销 / 撤 ...

  7. PyQt(Python+Qt)入门:Designer组件属性编辑界面中QWidget类相关属性详解

    本文适用人员:本文比较长,适合不理解Qt Designer部件属性的人员阅读或资料查找. 声明: 1.如果有人认为本文是简单的复制粘贴+翻译而成,敬请读本文最后的后记: 2.本文为老猿Python学习 ...

  8. Java 并发编程解析 | 如何正确理解Java领域中的内存模型,主要是解决了什么问题?

    写在开头 这些年,随着CPU.内存.I/O 设备都在不断迭代,不断朝着更快的方向努力.在这个快速发展的过程中,有一个核心矛盾一直存在,就是这三者的速度差异.CPU 和内存的速度差异可以形象地描述为:C ...

  9. java画二维坐标_在图形界面中绘制二维的坐标系统

    在图形界面中绘制二维的坐标系统,其中x轴位于绘图区正中,y轴位于绘图区的最左边.实现以下基本功能: (1)设计界面接受用户输入的实验数据,同时绘制数据点,每个数据点用一个小圆号表示.最后,用直线或曲线 ...

最新文章

  1. 贪吃蛇游戏(java)
  2. 邬贺铨:工业物联网的技术与前景
  3. Java并发程序设计(四)JDK并发包之同步控制
  4. ones--创建全1矩阵
  5. leetcode 5077. 按列翻转得到最大值等行数(Flip Columns For Maximum Number of Equal Rows)
  6. 5 Java 插入排序
  7. 当学术大家遇到技术大拿,如何攻克数据库应用头号难题?数位产学研大咖这样解读
  8. “支付功能”怎么测试?
  9. android.opengl.GLSurfaceView.Renderer概述
  10. 简析平衡树(四)——FHQ Treap
  11. 基于ssm的记账管理系统设计与实现【毕业设计jsp】
  12. Snipaste 截图工具快捷键大全
  13. 天气预报本地准时宝隐私政策
  14. 如果要做 Rietveld 分析,XRD时步长需要满足什么要求
  15. Android图片转base64加密在其它平台显示
  16. dell服务器设置CPU高性能,DellR720服务器提示cpu1 internal error (IERR)
  17. 神经网络原理与实例精解,神经网络计算工作原理
  18. CSS 样式继承 inherit 属性
  19. 大专生出身?java技术栈xmind
  20. L1-7 矩阵列平移

热门文章

  1. 干货丨机器学习指南(学习笔记哦,值得一看)
  2. csdn自带的在线编辑器如何让图片并排显示
  3. 【前沿科技】看完这篇文章前,你绝对想象不到欧美航空机器人竟然发展到这个程度了!...
  4. 美陆军将在2020年军演中测试人工智能新应用
  5. ARM与RISC-V之争,后起之秀的优势在哪儿?
  6. 知识图谱的前世今生:为什么我们需要知识图谱?
  7. 华为秘密作战计划曝光,重注研发AI芯片挑战英伟达,轮值董事长挂帅
  8. 旷视科技完成4.6亿美元C轮融资,打破商汤4.1亿美元单轮融资记录
  9. 选什么专业,最容易拿下互联网大厂 Offer?三个支付宝新人来支招
  10. Zoom 袁征码农逆袭:8 次申请美国签证被拒,独闯硅谷成亿万富翁