Swing


          天行健 君子以自強不息

          posts - 69, comments - 215, trackbacks - 0, articles - 16
             :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          監聽JComponent顯示事件

          Posted on 2010-02-04 22:09 zht 閱讀(1520) 評論(1)  編輯  收藏 所屬分類: Swing

              很多時候,我們需要在界面初始化以后對程序進行某些設置,舉個例子,當界面呈現出來以后,設置下SplitPane的的百分比(關于這個為什么必須這么處理請參考java源代碼)。很容易我們就想到給程序添加ComponentListener監聽,然后在監聽中作處理,如下所示

          panel.addComponentListener(new ComponentAdapter() {

                               public void componentShown(ComponentEvent e) {

                                      System.out.println("panel:shown");

                               }

                        });

          但是并沒有和我們想象的那樣,當組件在界面上顯示出來的時候firecomponentShown類型的事件的,下面我們通過研究源代碼分析下原因

          首先的問題是在什么地方會fireComponentEvent

          通過查看源代碼,我們可以看到實在Componentshow()方法中

          ComponentEvent e = new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN);

          Toolkit.getEventQueue().postEvent(e);

          具體代碼,請參考java源程序

          也就是說只有在組件調用到setVisible(true)的時候才會fireComponentEvent

          但是你會發現,即便是我們調用JComponentsetVisible(true),也不會監聽到shown事件

          原因主要是JComponent重載了setVisible方法

          如下

          public void setVisible(boolean aFlag) {

                  if(aFlag != isVisible()) {

                      super.setVisible(aFlag);

                      Container parent = getParent();

                      if(parent != null) {

                          Rectangle r = getBounds();

                          parent.repaint(r.x,r.y,r.width,r.height);

                      }

                     // Some (all should) LayoutManagers do not consider components

                     // that are not visible. As such we need to revalidate when the

                     // visible bit changes.

                     revalidate();

                  }

          }

          因為JComponentvisible屬性默認就是true,所以不會調用到ComponentsetVisible方法,所以也不會fireComponentEvent,當然,如果你調用下JComponentsetVisible(false)+setVisible(true)是會fireComponentEvent.COMPONENT_SHOWN事件的,(但是在里面很可能得不到當前組件的大小信息或者不能SplitPane設置分割比例,因為這個時候界面還沒有初始化),而且如果是JFrameJDialogJApplet等也是沒問題的,因為他們調用的都是ComponentsetVisible方法(所以給這些頂層組件添加ComponentListener是沒有問題的,都會監聽到)

          如果不想使用上述方法,還有另外一種方式就是添加HierarchyListener監聽,因為當頂層組件(JFrame,JDialog)setVisible(true)界面顯示的時候,里面都會fireHierarchyEvent,具體代碼如下(詳細代碼請參考Componentshow()方法)

                 createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED,

                                               this, parent,

                                               HierarchyEvent.SHOWING_CHANGED,

                                                    Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));

          createHierarchyEvents方法會在每個組件上fireHierarchyEvent,至于具體細節,有時間的可以dubug下,具體的解決方法如下

                 panel.addHierarchyListener(new HierarchyListener() {

                               public void hierarchyChanged(HierarchyEvent e) {

                                      if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {

                                             if (e.getComponent().isShowing()) {

                                                    System.out.println(panel.getBounds());

                                                    System.out.println("panel:hshow");

                                             }

                                             else {

                                                    System.out.println("panel:hhide");

                                             }

                                      }

                               }

                        });

          測試代碼如下
          public class Test {
              
          public static void main(String[] args) {
                  
          new Test();
              }


              
          public Test() {
                  
          final JPanel panel = new JPanel();
                  panel.addComponentListener(
          new ComponentAdapter() {
                      
          public void componentShown(ComponentEvent e) {
                          System.out.println(panel.getBounds());
                          System.out.println(
          "panel:shown");
                      }

                  }
          );
                  
          //        panel.setVisible(false);
                  
          //        panel.setVisible(true);
                  panel.addHierarchyListener(new HierarchyListener() {
                      
          public void hierarchyChanged(HierarchyEvent e) {
                          
          if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0{
                              
          if (e.getComponent().isShowing()) {
                                  System.out.println(panel.getBounds());
                                  System.out.println(
          "panel:hshow");
                              }

                              
          else {
                                  System.out.println(
          "panel:hhide");
                              }

                          }

                      }

                  }
          );

                  JFrame frame 
          = new JFrame();

                  frame.addComponentListener(
          new ComponentAdapter() {
                      
          public void componentShown(ComponentEvent e) {
                          System.out.println(
          "frame:shown");
                      }

                  }
          );

                  frame.setContentPane(panel);
                  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                  frame.setSize(
          500400);
                  frame.setVisible(
          true);
              }

          }

          主站蜘蛛池模板: 南乐县| 同仁县| 合水县| 大竹县| 乌拉特前旗| 宁蒗| 苏尼特左旗| 夏河县| 马龙县| 崇左市| 交口县| 石城县| 大理市| 汤阴县| 冕宁县| 且末县| 上栗县| 津市市| 南充市| 萨嘎县| 水富县| 友谊县| 八宿县| 连江县| 彭泽县| 古浪县| 宁明县| 岢岚县| 西贡区| 雅江县| 望城县| 竹溪县| 永济市| 含山县| 西乌珠穆沁旗| 元谋县| 红原县| 山阳县| 拉萨市| 泊头市| 荣成市|