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

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

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

    John Jiang

    a cup of Java, cheers!
    https://github.com/johnshajiang/blog

       :: 首頁 ::  :: 聯系 :: 聚合  :: 管理 ::
      131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
    數據加載模糊進度指示面板的實現與應用
    當在加載數據(或其它耗時工作)時,需要顯示一個進度指示面板,本文介紹了一種簡易的實現方式。(2009.11.30最后更新)

    對于許多Swing應用,在與用戶的交互過程中可能需要與數據庫進行通信(如,加載數據)。而這個過程往往比較耗時,為了不造成"假死"現象,一般都會顯示一個模糊進度指示器(不一定使用JProgressBar,簡單地用一個圖片代替即可),當數據加載完畢后,該進度指示器自動消失。
        一般地,該模糊進度指示器不會展示在一個彈出的對話框中(因為這樣不美觀),而是直接顯示在需要展示被加載數據的面板中,并且對該面板進行模糊處理。實現這一功能的關鍵就在于,在屏幕的同一區域內展示兩層面板:一層是展示數據的面板;另一層是展示進度指示器的面板。當加載數據時,顯示進度指示器面板,并模糊數據面板;當數據加載完畢后,隱藏進度指示器面板,并使數據面板清晰顯示。下面將使用org.jdesktop.swingx.StackLayout方式來實現上述功能。

    1. LoadingPanel--加載指示器面板
        首先創建一個加載指示器面板。如前所述,我們不必使用真正的進度條作為進度指示器,僅需要使用一張動態圖片來代替即可。LoadingPanel的完整代碼如下所示,
    public class LoadingPanel extends JPanel {

        
    private static final long serialVersionUID = 1962748329465603630L;

        
    private String mesg = null;

        
    public LoadingPanel(String mesg) {
            
    this.mesg = mesg;
            initUI();
            interceptInput();
            setOpaque(
    false);
            setVisible(
    false);
        }

        
    private void initUI() {
            JLabel label 
    = new JLabel(mesg);
            label.setHorizontalAlignment(JLabel.CENTER);
            label.setIcon(
    new ImageIcon(getClass().getResource("/path/to/spinner.gif")));

            setLayout(
    new BorderLayout());
            add(label, BorderLayout.CENTER);
        }

        
    private void interceptInput() {
            addMouseListener(
    new MouseAdapter() {});
            addMouseMotionListener(
    new MouseMotionAdapter() {});
            addKeyListener(
    new KeyAdapter() {});

            addComponentListener(
    new ComponentAdapter() {
                @Override
                
    public void componentShown(ComponentEvent e) {
                    requestFocusInWindow();
                }
            });
            setFocusTraversalKeysEnabled(
    false);
        }
    }
    上述代碼很容易理解,LoadingPanel中僅有一個JLabel,它會展示一張圖片(spinner.gif)及一段信息。但有兩段代碼需要特別說明:
    [1]構造器中的兩行代碼

    setVisible(false);
    setOpaque(
    false);
    LoadingPanel只在加載數據時才顯示,其它時候是不顯示的,所以它默認不可見。另外,在顯示LoadingPanel的同時,我們仍然希望能看到數據面板,所以LoadingPanel應該是透明的。
    [2]interceptInput方法
    當LoadingPanel顯示之后,我們不希望用戶還能夠操作數據面板,那么就需要屏蔽掉用戶(鼠標,鍵盤)輸入。
    addMouseListener(new MouseAdapter() {});
    addMouseMotionListener(
    new MouseMotionAdapter() {});
    addKeyListener(
    new KeyAdapter() {});
    上述三行代碼就使得LoadingPanel能捕獲所有的鼠標與鍵盤事件,并忽略掉它們。但僅僅如此還不夠,在展示LoadingPanel時,數據面板中的某個UI組件很可能已經獲得焦點了,那么用戶仍然可以通過鍵盤操控數據面板中的組件(因為系統會把鍵盤事件發送給當前獲取焦點的組件)。而且,即使數據面板中沒有任何組件獲得焦點,用戶仍然可以通過Tab鍵把焦點轉移到數據面板中的組件上。為了阻止這一操作,還需要加上如下幾行代碼,
    addComponentListener(new ComponentAdapter() { // 一旦LoadingPanel可見,即獲取焦點
        @Override
        
    public void componentShown(ComponentEvent e) {
            requestFocusInWindow();
        }
    });
    setFocusTraversalKeysEnabled(
    false); // 阻止用戶轉移焦點

    2. 示例程序

        在此處的示例程序中,數據面板(dataPanel)中僅有一個按鈕,當點擊該按鈕時會顯示loadingPanel,且模糊掉dataPanel,并會啟動一個新的線程,該線程會在睡眠大約3秒(模擬耗時的數據加載工作)之后隱藏loadingPanel,且使dataPanel重新清晰可見。
        值得注意的是,該示例程序使用了SwingX中的兩個組件:JXPanelStackLayout。JXPanel提供了一個方法(setAlpha)以方便地設置Panel的透明度(Alpha值);而StackLayout允許在同一塊區域內添加多層組件,并能同時展示所有層的組件(而,CardLayout一次只能顯示某一層的組件)。完整的示例程序如下所示,
    public class LoadDataDemo extends JFrame {

        
    private static final long serialVersionUID = 5927602404779391420L;

        
    private JXPanel dataPanel = null// 使用org.jdesktop.swingx.JXPanel,以方便設置清晰度

        
    private LoadingPanel loadingPanel = null;

        
    public LoadDataDemo() {
            
    super("LoadData Demo");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            initUI();
        }

        
    private void initUI() {
            JButton button 
    = new JButton("Load Data");
            button.addActionListener(handler);
            dataPanel 
    = new JXPanel(new FlowLayout(FlowLayout.CENTER));
            dataPanel.add(button);

            loadingPanel 
    = new LoadingPanel("Loading");

            
    // 使用org.jdesktop.swingx.StackLayout,將loadingPanel置于dataPanel的上方
            JPanel centerPanel = new JXPanel(new StackLayout());
            centerPanel.add(dataPanel, StackLayout.TOP);
            centerPanel.add(loadingPanel, StackLayout.TOP);

            Container container 
    = getContentPane();
            container.setLayout(
    new BorderLayout());
            container.add(centerPanel, BorderLayout.CENTER);
        }

        
    transient private ActionListener handler = new ActionListener() {

            
    public void actionPerformed(ActionEvent e) {
               
    // 將dataPanel及其子組件的清晰度設置為50%;并顯示loadingPanel
                dataPanel.setAlpha(0.5F);
                loadingPanel.setVisible(
    true);

                Thread thread 
    = new Thread() {
                    
    public void run() {
                        
    try {
                            Thread.sleep(
    3000L); // 睡眠約3秒鐘,以模擬加載數據的過程
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                       
    // 數據加載完畢后,重新隱藏loadingPanel;并使dataPanel及其子組件重新清晰可見
                        loadingPanel.setVisible(false);
                        dataPanel.setAlpha(1F);
                    };
                };
                thread.start();
            }
        };

        
    public static void main(String[] args) {
            LoadDataDemo demo 
    = new LoadDataDemo();
            demo.setSize(
    new Dimension(400300));
            demo.setVisible(
    true);
        }
    }

    3. 不使用SwingX

        SwingX為我們提供了一系列功能強大,使用簡易的Swing擴展組件,我強烈建議你去使用它。但若因故,你不準備使用它時,我們仍然有替代的解決方案,但此處僅簡述一二。
    [1]對于設置Alpha值,需要創建一個繼承自JPanel的DataPanel類,覆寫paintComponent方法,在其中使用Alpha合成,
    Graphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
    [2]對于StackLayout,我們可以使用GlassPane(玻璃窗格)或LayeredPane(分層窗格)進行替換,將LoadingPanel設置為GlassPane或LayeredPanel中的一層。由于一個JFrame只有一個GlassPane,為了程序的靈活性,一般首選使用LayeredPane。

    posted on 2009-11-29 20:33 John Jiang 閱讀(2194) 評論(5)  編輯  收藏 所屬分類: JavaSE 、Java 、Swing原創

    評論

    # re: 數據加載模糊進度指示面板的實現與應用(原) 2009-12-01 12:18 創意禮品
    非常好的文章,謝謝樓主分享!非常好的文章,謝謝樓主分享!  回復  更多評論
      

    # re: 數據加載模糊進度指示面板的實現與應用(原) 2009-12-01 20:12 BeanSoft
    兄弟 這種情況我個人覺得用 JRootPane 會更好一些.

    不過我的代碼沒考慮鍵盤的事件 呵呵 很早以前自己搞的玩意了

    package beansoft.swing;

    import javax.swing.*;

    import java.awt.BorderLayout;
    import java.awt.Cursor;
    import java.awt.FlowLayout;
    import java.awt.event.*;

    /**
    * We have to provide our own glass pane so that it can paint a loading
    * dialog and then the user can see the progress but can't operation
    * the GUI, it's a transparent pane so the below contents is visible.
    *
    * Also please refer to articles by Sun - How to Use Root Panes:
    * {@link http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html}
    * @author Jacky Liu
    * @version 1.0 2006-08
    */
    public class LoadingGlassPane extends JPanel {
    private static final long serialVersionUID = 1L;
    /**
    * A label displays status text and loading icon.
    */
    private JLabel statusLabel = new JLabel("Reading data, please wait...");

    public LoadingGlassPane() {
    try {
    statusLabel.setIcon(new ImageIcon(getClass().getResource(
    "loading.gif")));
    } catch (RuntimeException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
    }

    statusLabel.setHorizontalAlignment(JLabel.CENTER);

    // Must add a mouse listener, otherwise the event will not be
    // captured
    this.addMouseListener(new java.awt.event.MouseAdapter() {
    public void mousePressed(MouseEvent e) {
    }
    });

    this.setLayout(new BorderLayout());

    this.add(statusLabel);
    // Transparent
    setOpaque(false);
    }

    public JLabel getStatusLabel() {
    return statusLabel;
    }

    /**
    * Set the text to be displayed on the glass pane.
    *
    * @param text
    */
    public void setStatusText(final String text) {
    SwingUtilities.invokeLater(new Runnable() {
    public void run() {
    statusLabel.setText(text);
    }
    });
    }

    /**
    * Install this to the jframe as glass pane.
    * @param frame
    */
    public void installAsGlassPane(JFrame frame) {
    frame.setGlassPane(this);
    }

    /**
    * A small demo code of how to use this glasspane.
    * @param args
    */
    public static void main(String[] args) {
    JFrame frame = new JFrame("Test GlassPane");
    final LoadingGlassPane glassPane = new LoadingGlassPane();
    glassPane.installAsGlassPane(frame);

    JButton button = new JButton("Test Query");

    button.addActionListener(new ActionListener() {

    public void actionPerformed(ActionEvent e) {
    // Call in new thread to allow the UI to update
    Thread th = new Thread() {
    public void run() {
    glassPane.setVisible(true);
    glassPane.setCursor(new Cursor(Cursor.WAIT_CURSOR));
    // TODO Long time operation here
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    glassPane.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    glassPane.setVisible(false);
    }
    };

    th.start();
    }

    });

    frame.getContentPane().setLayout(new FlowLayout());
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(button);

    frame.setSize(200, 200);
    frame.setVisible(true);

    }

    }  回復  更多評論
      

    # re: 數據加載模糊進度指示面板的實現與應用(原) 2009-12-02 08:50 Sha Jiang
    @BeanSoft
    我瀏覽了一下你的代碼,你使用的方法就是我在文章末尾提到的"將LoadingPanel設置為GlassPane..."這種方法。
    一般地,若要使用GlassPane時,最好優先考慮使用LayeredPane。
    但我必須要說,使用StackLayout最靈活性,也最簡單。  回復  更多評論
      

    # re: 數據加載模糊進度指示面板的實現與應用(原) 2009-12-20 01:25 Krista31
    Click <a href="http://www.4writers.net">freelance writing </a> when you want get some knowledge just about this topic.   回復  更多評論
      

    # re: 數據加載模糊進度指示面板的實現與應用(原) 2011-02-11 21:14 外貿女裝批發
    正好有一朋友問到這個問題,就借大作獻佛了。呵呵。多謝。~~  回復  更多評論
      

    主站蜘蛛池模板: 中文字幕免费视频精品一| 深夜A级毛片视频免费| 一级毛片aaaaaa免费看| 亚洲男人的天堂www| 一级做a爱过程免费视| 国产亚洲av片在线观看18女人| 阿v免费在线观看| 亚洲国产一区二区视频网站| 一区二区三区免费在线视频| 亚洲一区二区三区香蕉| 99精品免费视品| 亚洲人成在线观看| 亚洲三级高清免费| 亚洲成AV人片高潮喷水| 亚洲情a成黄在线观看| 免费无码H肉动漫在线观看麻豆| 亚洲AV无码成人网站久久精品大| 最近中文字幕mv免费高清在线 | 美女视频黄是免费的网址| 国产成人精品日本亚洲专区6| 麻豆精品国产免费观看| 国产99久久亚洲综合精品| 在线观看亚洲天天一三视| 午夜爽爽爽男女免费观看影院| 亚洲国产人成在线观看| 日本高清免费网站| 久久国产乱子免费精品| 亚洲人成人无码.www石榴 | 久久久影院亚洲精品| 成年人视频免费在线观看| 久久亚洲精品高潮综合色a片| 亚洲中文无韩国r级电影| 日本亚洲欧洲免费天堂午夜看片女人员 | 亚洲砖码砖专无区2023| 亚洲VA综合VA国产产VA中| 99免费观看视频| 日韩精品亚洲专区在线影视| 日韩精品亚洲人成在线观看| 免费无码一区二区三区蜜桃大 | 一级女人18片毛片免费视频| 亚洲黄色高清视频|