<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
    博主,"為了讓畫面不會卡住,我們來修改代碼,將耗時的工作放在一個線程里去做。"為什么這樣子就不會卡住呢,懇請解答  回復  更多評論
      

    主站蜘蛛池模板: **俄罗斯毛片免费| 成人毛片18女人毛片免费视频未| 亚洲av永久无码精品漫画| 18禁无遮挡无码国产免费网站| 亚洲AV综合色区无码二区偷拍| www.91亚洲| 日韩中文字幕免费视频| 亚洲国产美女精品久久久| 亚洲男人的天堂www| 国产精品免费观看| 三级片免费观看久久| 亚洲精品在线免费观看| 免费在线观看亚洲| 久久精品毛片免费观看| 精品久久久久久亚洲综合网| 久久精品国产亚洲AV网站| 日韩精品免费一区二区三区| 国产永久免费高清在线| 亚洲AV成人一区二区三区观看| 亚洲av无码潮喷在线观看| 免费一级成人毛片| 国产成人免费午夜在线观看| 有色视频在线观看免费高清在线直播| 亚洲激情校园春色| 在线亚洲精品自拍| 国产小视频在线观看免费| 亚洲日本在线免费观看| 国产免费A∨在线播放| 亚洲AV男人的天堂在线观看| 亚洲ⅴ国产v天堂a无码二区| 可以免费观看一级毛片黄a| 在线观看永久免费| 久久一区二区免费播放| 日韩亚洲综合精品国产| 亚洲一区二区三区免费观看| 久久亚洲AV午夜福利精品一区| 亚洲国产成人乱码精品女人久久久不卡| 在线观看视频免费完整版| 久久久久国产免费| 免费无码作爱视频| 免费国产高清毛不卡片基地|