很多時候,我們需要在界面初始化以后對程序進行某些設置,舉個例子,當界面呈現(xiàn)出來以后,設置下SplitPane的的百分比(關于這個為什么必須這么處理請參考java源代碼)。很容易我們就想到給程序添加ComponentListener監(jiān)聽,然后在監(jiān)聽中作處理,如下所示
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源程序
也就是說只有在組件調(diào)用到setVisible(true)的時候才會fire出ComponentEvent
但是你會發(fā)現(xiàn),即便是我們調(diào)用JComponent的setVisible(true),也不會監(jiān)聽到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();
}
}
因為JComponent的visible屬性默認就是true,所以不會調(diào)用到Component的setVisible方法,所以也不會fire出ComponentEvent,當然,如果你調(diào)用下JComponent的setVisible(false)+setVisible(true)是會fire出ComponentEvent.COMPONENT_SHOWN事件的,(但是在里面很可能得不到當前組件的大小信息或者不能SplitPane設置分割比例,因為這個時候界面還沒有初始化),而且如果是JFrame,JDialog,JApplet等也是沒問題的,因為他們調(diào)用的都是Component的setVisible方法(所以給這些頂層組件添加ComponentListener是沒有問題的,都會監(jiān)聽到)
如果不想使用上述方法,還有另外一種方式就是添加HierarchyListener監(jiān)聽,因為當頂層組件(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,至于具體細節(jié),有時間的可以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");
}
}
}
});
測試代碼如下









































