默认
打赏 发表评论 2
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
如何实现监听JComponent的显示事件
阅读(26315) | 评论(2 收藏 淘帖 1
微信扫一扫关注!

引言


很多时候,我们需要在界面初始化以后对程序进行某些设置,举个例子,当界面呈现出来以后,设置下SplitPane的的百分比(关于这个为什么必须这么处理请参考java源代码)。很容易我们就想到给程序添加ComponentListener监听,然后在监听中作处理,如下所示:
panel.addComponentListener(new ComponentAdapter() {
        public void componentShown(ComponentEvent e) {
                System.out.println("panel:shown");
        }
});

但是并没有和我们想象的那样,当组件在界面上显示出来的时候fire出componentShown类型的事件的,下面我们通过研究源代码分析下原因。

原因分析


首先的问题是在什么地方会fire出ComponentEvent,通过查看源代码,我们可以看到实在Component的show()方法中:
ComponentEvent e = new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN);
Toolkit.getEventQueue().postEvent(e);
具体代码,请参考java源程序。

也就是说只有在组件调用到setVisible(true)的时候才会fire出ComponentEvent,但是你会发现,即便是我们调用JComponent的setVisible(true),也不会监听到shown事件。原因主要是JComponent重载了setVisible方法,具体如下:
ublic 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();
        }
}
因为JComponent的visible属性默认就是true,所以不会调用到Component的setVisible方法,所以也不会fire出ComponentEvent,当然,如果你调用下JComponent的setVisible(false)+setVisible(true)是会fire出ComponentEvent.COMPONENT_SHOWN事件的,(但是在里面很可能得不到当前组件的大小信息或者不能SplitPane设置分割比例,因为这个时候界面还没有初始化),而且如果是JFrame,JDialog,JApplet等也是没问题的,因为他们调用的都是Component的setVisible方法(所以给这些顶层组件添加ComponentListener是没有问题的,都会监听到)。

使用HierarchyListener实现监听


还有另外一种方式就是添加HierarchyListener监听,因为当顶层组件(JFrame,JDialog等)setVisible(true)界面显示的时候,里面都会fire出HierarchyEvent,具体代码如下(详细代码请参考Component的show()方法):
createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED,
          this, parent,
          HierarchyEvent.SHOWING_CHANGED,
          Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
而createHierarchyEvents方法会在每个组件上fire出HierarchyEvent,至于具体细节,有时间的可以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(500, 400);
        frame.setVisible(true);
    }
}

运行结果:
    C:\java>java Test
    java.awt.Rectangle[x=0,y=0,width=492,height=373]
    panel:hshow
    frame:shown

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

标签:Java Swing
上一篇:Java Swing组件的Model介绍下一篇:Java Swing经典神书:Swing Hacks电子书下载(含源码)
推荐方案
评论 2
好厉害的样子
写得很通俗易懂!
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部