侦听后代组件层次结构更改

时间:2014-08-29 15:10:59

标签: java swing jpanel listener jcomponent

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();
    }
}

1 个答案:

答案 0 :(得分:1)

一种可能的解决方案是使用单个ContainerListener将自己添加到添加到" root"的容器中。容器(并且,为了完整性,也将自己从被移除的容器中移除,对于必要的情况)。

所以你基本上可以创建一个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());
    }

}