<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    ALL is Well!

    敏捷是一條很長的路,摸索著前進著

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      30 隨筆 :: 23 文章 :: 71 評論 :: 0 Trackbacks

    現在我們要做一個簡單的界面。

    包括一個進度條、一個輸入框、開始和停止按鈕。

    需要實現的功能是:

    當點擊開始按鈕,則更新進度條,并且在輸入框內把完成的百分比輸出(這里只做例子,沒有真正去做某個工作)

    import java.awt.FlowLayout;   
    import java.awt.event.ActionEvent;   
    import java.awt.event.ActionListener;   
    import javax.swing.JButton;   
    import javax.swing.JFrame;   
    import javax.swing.JProgressBar;   
    import javax.swing.JTextField;   
    public class SwingThreadTest1 extends JFrame {   
        
    private static final long serialVersionUID = 1L;   
        
    private static final String STR = "Completed : ";   
        
    private JProgressBar progressBar = new JProgressBar();   
        
    private JTextField text = new JTextField(10);   
        
    private JButton start = new JButton("Start");   
        
    private JButton end = new JButton("End");   
        
    private boolean flag = false;   
        
    private int count = 0;   
        
    public SwingThreadTest1() {   
            
    this.setLayout(new FlowLayout());   
            add(progressBar);   
            text.setEditable(
    false);   
            add(text);   
            add(start);   
            add(end);   
            start.addActionListener(
    new Start());   
            end.addActionListener(
    new End());   
        }
       
               
        
    private void go() {   
            
    while (count < 100{   
                
    try {   
                    Thread.sleep(
    100);//這里比作要完成的某個耗時的工作   
                }
     catch (InterruptedException e) {   
                    e.printStackTrace();   
                }
       
                             
    //更新進度條和輸入框   
                if (flag) {   
                    count
    ++;   
                    progressBar.setValue(count);   
                    text.setText(STR 
    + String.valueOf(count) + "%");   
                }
       
            }
       
        }
       
        
    private class Start implements ActionListener {   
            
    public void actionPerformed(ActionEvent e) {   
                flag 
    = true;//設置開始更新的標志   
                go();//開始工作   
            }
       
        }
       
        
    private class End implements ActionListener {   
            
    public void actionPerformed(ActionEvent e) {   
                flag 
    = false;//停止   
            }
       
        }
       
        
    public static void main(String[] args) {   
            SwingThreadTest1 fg 
    = new SwingThreadTest1();   
            fg.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   
            fg.setSize(
    300100);   
            fg.setVisible(
    true);   
        }
       
    }

    運行代碼發現,

    現象1:當點擊了開始按鈕,畫面就卡住了。按鈕不能點擊,進度條沒有被更新,輸入框上也沒有任何信息。

    原因分析:Swing是線程不安全的,是單線程的設計,所以只能從事件派發線程訪問將要在屏幕上繪制的Swing組件。ActionListener的actionPerformed方法是在事件派發線程中調用執行的,而點擊了開始按鈕后,執行了go()方法,在go()里,雖然也去執行了更新組件的方法

    progressBar.setValue(count);

    text.setText(STR + String.valueOf(count) + "%");

    但由于go()方法直到循環結束,它并沒有返回,所以更新組件的操作一直沒有被執行,這就造成了畫面卡住的現象。

    現象2:過了一段時間(go方法里的循環結束了)后,畫面又可以操作,并且進度條被更新,輸入框也出現了我們想看到的信息。

    原因分析:通過在現象1的分析,很容易聯想到,當go()方法返回了,則其他的線程(更新組件)可以被派發了,所以畫面上的組件被更新了。

    為了讓畫面不會卡住,我們來修改代碼,將耗時的工作放在一個線程里去做。

     


    代碼2:

     

     1import java.awt.FlowLayout;   
     2import java.awt.event.ActionEvent;   
     3import java.awt.event.ActionListener;   
     4import javax.swing.JButton;   
     5import javax.swing.JFrame;   
     6import javax.swing.JProgressBar;   
     7import javax.swing.JTextField;   
     8public class SwingThreadTest2 extends JFrame {   
     9    private static final long serialVersionUID = 1L;   
    10    private static final String STR = "Completed : ";   
    11    private JProgressBar progressBar = new JProgressBar();   
    12    private JTextField text = new JTextField(10);   
    13    private JButton start = new JButton("Start");   
    14    private JButton end = new JButton("End");   
    15    private boolean flag = false;   
    16    private int count = 0;   
    17       
    18    GoThread t = null;   
    19    public SwingThreadTest2() {   
    20        this.setLayout(new FlowLayout());   
    21        add(progressBar);   
    22        text.setEditable(false);   
    23        add(text);   
    24        add(start);   
    25        add(end);   
    26        start.addActionListener(new Start());   
    27        end.addActionListener(new End());   
    28    }
       
    29    private void go() {   
    30        while (count < 100{   
    31            try {   
    32                Thread.sleep(100);   
    33            }
     catch (InterruptedException e) {   
    34                e.printStackTrace();   
    35            }
       
    36            if (flag) {   
    37                count++;   
    38                System.out.println(count);   
    39                progressBar.setValue(count);   
    40                text.setText(STR + String.valueOf(count) + "%");   
    41            }
       
    42        }
       
    43    }
       
    44    private class Start implements ActionListener {   
    45        public void actionPerformed(ActionEvent e) {   
    46            flag = true;   
    47            if(t == null){   
    48                t = new GoThread();   
    49                t.start();   
    50            }
       
    51        }
       
    52    }
       
    53    //執行復雜工作,然后更新組件的線程   
    54    class GoThread extends Thread{   
    55        public void run() {   
    56            //do something   
    57            go();   
    58        }
       
    59    }
       
    60    private class End implements ActionListener {   
    61        public void actionPerformed(ActionEvent e) {   
    62            flag = false;   
    63        }
       
    64    }
       
    65    public static void main(String[] args) {   
    66        SwingThreadTest2 fg = new SwingThreadTest2();   
    67        fg.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   
    68        fg.setSize(300100);   
    69        fg.setVisible(true);   
    70    }
       
    71}


    我們執行了程序,結果和我們想要的一樣,畫面不會卡住了。

    那這個程序是否沒有問題了呢?

    我們自定義了一個線程GoThread,在這里我們完成了那些耗時的工作,可以看作是“工作線程”,

    而對于組件的更新,我們也放在了“工作線程”里完成了。

    在這里,在事件派發線程以外的線程里設置進度條,是一個危險的操作,運行是不正常的。(對于輸入框組件的更新是安全的。)

    只有從事件派發線程才能更新組件,根據這個原則,我們來修改我們現有代碼。

     1import java.awt.FlowLayout;   
     2import java.awt.event.ActionEvent;   
     3import java.awt.event.ActionListener;   
     4import javax.swing.JButton;   
     5import javax.swing.JFrame;   
     6import javax.swing.JProgressBar;   
     7import javax.swing.JTextField;   
     8import javax.swing.SwingUtilities;   
     9public class SwingThreadTest3 extends JFrame {   
    10    private static final long serialVersionUID = 1L;   
    11    private static final String STR = "Completed : ";   
    12    private JProgressBar progressBar = new JProgressBar();   
    13    private JTextField text = new JTextField(10);   
    14    private JButton start = new JButton("Start");   
    15    private JButton end = new JButton("End");   
    16    private boolean flag = false;   
    17    private int count = 0;   
    18       
    19    private GoThread t = null;   
    20       
    21    private Runnable run = null;//更新組件的線程   
    22    public SwingThreadTest3() {   
    23        this.setLayout(new FlowLayout());   
    24        add(progressBar);   
    25        text.setEditable(false);   
    26        add(text);   
    27        add(start);   
    28        add(end);   
    29        start.addActionListener(new Start());   
    30        end.addActionListener(new End());   
    31           
    32        run = new Runnable(){//實例化更新組件的線程   
    33            public void run() {   
    34                progressBar.setValue(count);   
    35                text.setText(STR + String.valueOf(count) + "%");   
    36            }
       
    37        }
    ;   
    38    }
       
    39    private void go() {   
    40        while (count < 100{   
    41            try {   
    42                Thread.sleep(100);   
    43            }
     catch (InterruptedException e) {   
    44                e.printStackTrace();   
    45            }
       
    46            if (flag) {   
    47                count++;   
    48                SwingUtilities.invokeLater(run);//將對象排到事件派發線程的隊列中   
    49            }
       
    50        }
       
    51    }
       
    52    private class Start implements ActionListener {   
    53        public void actionPerformed(ActionEvent e) {   
    54            flag = true;   
    55            if(t == null){   
    56                t = new GoThread();   
    57                t.start();   
    58            }
       
    59        }
       
    60    }
       
    61       
    62    class GoThread extends Thread{   
    63        public void run() {   
    64            //do something   
    65            go();   
    66        }
       
    67    }
       
    68    private class End implements ActionListener {   
    69        public void actionPerformed(ActionEvent e) {   
    70            flag = false;   
    71        }
       
    72    }
       
    73    public static void main(String[] args) {   
    74        SwingThreadTest3 fg = new SwingThreadTest3();   
    75        fg.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   
    76        fg.setSize(300100);   
    77        fg.setVisible(true);   
    78    }
       
    79}


    解釋:SwingUtilities.invokeLater()方法使事件派發線程上的可運行對象排隊。當可運行對象排在事件派發隊列的隊首時,就調用其run方法。其效果是允許事件派發線程調用另一個線程中的任意一個代碼塊。

    還有一個方法SwingUtilities.invokeAndWait()方法,它也可以使事件派發線程上的可運行對象排隊。

    他們的不同之處在于:SwingUtilities.invokeLater()在把可運行的對象放入隊列后就返回,而SwingUtilities.invokeAndWait()一直等待知道已啟動了可運行的run方法才返回。如果一個操作在另外一個操作執行之前必須從一個組件獲得信息,則應使用SwingUtilities.invokeAndWait()方法。

    ----2009年02月16日

    本文為原創,歡迎轉載,轉載請注明出處BlogJava

    posted on 2010-09-01 12:05 李 明 閱讀(1038) 評論(3)  編輯  收藏 所屬分類: J2SEJava

    評論

    # re: Swing 線程之SwingUtilities.invokeLater() [未登錄] 2011-02-24 16:31 llq
    樓主寫得很好,我是一名初學者,這個問題困擾了我一段時間,看了你的文章豁然開朗,謝謝  回復  更多評論
      

    # re: Swing 線程之SwingUtilities.invokeLater() 2011-02-28 11:07 Ronaldo
    @llq
    這博文我在CSDN早就發過了。  回復  更多評論
      

    # re: Swing 線程之SwingUtilities.invokeLater() 2011-09-05 12:26 sysu_mjc
    博主,"為了讓畫面不會卡住,我們來修改代碼,將耗時的工作放在一個線程里去做。"為什么這樣子就不會卡住呢,懇請解答  回復  更多評論
      

    主站蜘蛛池模板: 亚洲AV成人噜噜无码网站| 国产精品亚洲视频| 亚洲高清免费在线观看| 91制片厂制作传媒免费版樱花| 亚洲精品在线视频观看| 免费人成激情视频在线观看冫| 亚洲精品少妇30p| 国产免费一区二区三区在线观看| 免费能直接在线观看黄的视频| 久久精品国产亚洲香蕉| 久久久久国产精品免费看| 亚洲激情中文字幕| 国产a视频精品免费观看| 亚洲AV无码无限在线观看不卡| 夭天干天天做天天免费看| 亚洲av永久无码精品秋霞电影秋| 全免费A级毛片免费看网站| 国产AV日韩A∨亚洲AV电影| 精品国产无限资源免费观看| 亚洲乱码一二三四五六区| 成年女人永久免费观看片| jizz免费在线观看| 亚洲精品国产成人专区| 插B内射18免费视频| 特级毛片爽www免费版| 久久精品国产亚洲| 女人让男人免费桶爽30分钟| 一本岛v免费不卡一二三区| 亚洲av之男人的天堂网站| 久久久久久免费视频| 成人免费视频一区二区| 亚洲AV天天做在线观看| 手机在线毛片免费播放| xvideos永久免费入口| 亚洲男人电影天堂| 亚洲 无码 在线 专区| 99久久免费精品视频| 99亚洲乱人伦aⅴ精品| 久久久久久久久亚洲| 国产一区二区三区无码免费| 成年免费a级毛片免费看无码|