2014-08-29 21 views
1

JComponent有没有办法让其后代组件层次结构中的添加/删除变更通知?收听后代组件层次结构变化

例如,在下面的代码中有一个addChild按钮,它会将新的子项JPanel添加到根或添加的最后一个面板。我希望根面板获得此通知。有点像HierarchyListener,但其他方式或ContainerListener不仅仅是听到直接的孩子。

public class DecendantHierarchyListening extends JFrame { 

    private final JPanel root = createChildPanel(null); 

    public JPanel leafComponent = root; 

    public DecendantHierarchyListening() { 
     super("title"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     JComponent buttons = new JPanel(); 

     JPanel panel = new JPanel(new BorderLayout()); 
     panel.add(createAddChildButton(buttons), BorderLayout.NORTH); 
     panel.add(root, BorderLayout.CENTER); 

     getContentPane().add(panel); 
    } 

    private Button createAddChildButton(JComponent buttons) { 
     Button button = new Button("AddChild"); 
     buttons.add(button); 
     button.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       leafComponent = (JPanel) leafComponent 
         .add(createChildPanel(leafComponent)); 
       DecendantHierarchyListening.this.invalidate(); 
       DecendantHierarchyListening.this.validate(); 
       DecendantHierarchyListening.this.repaint(); 
      } 
     }); 
     return button; 
    } 

    public static JPanel createChildPanel(Container parent) { 
     Color[] colors = new Color[] { Color.RED, Color.BLUE, Color.GREEN }; 
     JPanel panel = new JPanel(new BorderLayout()); 
     panel.setPreferredSize(new Dimension(200, 200)); 
     Color color; 
     if (parent == null) { 
      color = Color.GREEN; 
     } else { 
      int distance = 1; 
      parent = parent.getParent(); 
      while (parent != null) { 
       distance++; 
       parent = parent.getParent(); 
      } 

      color = colors[distance % colors.length]; 
     } 

     panel.setBorder(BorderFactory.createLineBorder(color, 2)); 
     return panel; 
    } 

    public static void runDemo() { 
     JFrame f = new DecendantHeirarchyListening(); 
     f.pack(); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     DecendantHierarchyListening.runDemo(); 
    } 
} 
+0

我想你可以解决这很容易地。为什么你甚至想听一些不影响特定组件的事件?例如,您可以为您想要接收通知的所有容器重新使用一个ContainerListener。在技​​术上向组件的孩子添加孩子不会影响它(除非您对第一个孩子进行了调整)。这是另一种方法:使用层次结构“中间”的组件通知您的顶级组件。 – J4v4 2014-08-29 15:23:45

回答

1

一种可能的解决办法是使用单个ContainerListener,增加本身,以被添加到“根”的容器(和,只是为了完整性的容器,还除去本身从被删除的容器中,这是必要的情况)。

所以你基本上可以创建一个ContainerListener并将其添加到根容器。只要此侦听器收到有关添加的新子组件的通知,它就会将其自身添加到此组件(如果它是容器)。之后,当组件被添加到子组件时,监听器将被通知,并且可能再次将自己添加到孙子中,依此类推。

我在这里勾勒它的一个例子:

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.Container; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.ContainerEvent; 
import java.awt.event.ContainerListener; 

import javax.swing.BorderFactory; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class DescendantHierarchyListening extends JPanel 
{ 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       createAndShowGUI(); 
      } 
     }); 
    } 

    public static void createAndShowGUI() 
    { 
     JFrame f = new JFrame(); 
     f.add(new DescendantHierarchyListening()); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setSize(400, 400); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    ContainerListener containerListener = new ContainerListener() 
    { 
     @Override 
     public void componentAdded(ContainerEvent e) 
     { 
      Component child = e.getChild(); 
      System.out.println("Added " + child); 
      System.out.println(" to " + e.getContainer()); 

      if (child instanceof Container) 
      { 
       Container container = (Container)child; 
       container.addContainerListener(this); 
      } 
     } 

     @Override 
     public void componentRemoved(ContainerEvent e) 
     { 
      Component child = e.getChild(); 
      System.out.println("Removed " + child); 
      System.out.println(" from " + e.getContainer()); 
      if (child instanceof Container) 
      { 
       Container container = (Container)child; 
       container.removeContainerListener(this); 
      } 
     } 
    }; 

    private final JPanel root; 
    public JPanel leafComponent; 

    public DescendantHierarchyListening() 
    { 
     super(new BorderLayout()); 

     JButton button = createAddChildButton(); 
     add(button, BorderLayout.NORTH); 

     root = createChildPanel(null); 
     root.addContainerListener(containerListener); 

     add(root, BorderLayout.CENTER); 
     leafComponent = root; 
    } 

    private JButton createAddChildButton() 
    { 
     JButton button = new JButton("AddChild"); 
     button.addActionListener(new ActionListener() 
     { 
      @Override 
      public void actionPerformed(ActionEvent e) 
      { 
       JPanel child = createChildPanel(leafComponent); 
       leafComponent.add(child); 
       leafComponent = child; 
       revalidate(); 
      } 
     }); 
     return button; 
    } 

    public JPanel createChildPanel(final Container parent) 
    { 
     JPanel panel = new JPanel(new BorderLayout()) 
     { 
      @Override 
      public String toString() 
      { 
       return "Child of " + parent; 
      } 
     }; 
     Color color = getColor(parent); 
     panel.setBorder(BorderFactory.createLineBorder(color, 2)); 
     return panel; 
    } 

    private static Color getColor(Component c) 
    { 
     if (c == null) 
     { 
      return Color.GREEN; 
     } 
     Color[] colors = new Color[] 
     { Color.RED, Color.BLUE, Color.GREEN }; 
     int d = getDepth(c); 
     return colors[d % colors.length]; 
    } 

    private static int getDepth(Component c) 
    { 
     if (c == null) 
     { 
      return 0; 
     } 
     return 1 + getDepth(c.getParent()); 
    } 

} 
+0

感谢Marco,这或多或少是我想出来的。我还需要添加一些遍历后代组件的代码,当componentAdded/componentRemoved被称为向这些组件添加/移除containerListener时,虽然在我的示例中这不是必须的。感谢你的回答。 – Jamesy82 2014-08-30 00:40:49