Swing makes it very easy to control and modify simple components like JLabel or JButton. It gets trickier when you customize a compound component like JTree or JTable. Unlike a simple component, JTable consists of multiple subcomponents like table header, renderer and editor, so actually JTable is not a single component but a container with several descendants.

Imagine that you want to customize a JLabel to change its border when you move the mouse cursor over it. You just add a mouse listener and switch the border there back and forth. Now let's make the task a bit more challenging - you want make the same trick with a JPanel which contains a JButton inside.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class JPanelTest extends JFrame { 
    public JPanelTest() {
        super("JPanel test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JPanel panel = new JPanel();
        add(panel);
        
        panel.addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                panel.setBorder(
                BorderFactory.createLineBorder(Color.GREEN, 5));
            }

            public void mouseExited(MouseEvent e) {
                panel.setBorder(null);
            }
        });
        
        panel.setLayout(new GridLayout(0, 2));
        panel.add(new JButton("JButton"));
        
        setSize(300, 300);
        setLocationRelativeTo(null);
    }

    public static void main(String... args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new JPanelTest().setVisible(true);
            }
        });
    }
}

 Running this test you will see that when the mouse cursor enters the child button the parent panel receives the mouseExited event and the border is gone.

http://swinghelper.java.net/bin/blog/listeners/border.png http://swinghelper.java.net/bin/blog/listeners/noborder.png

To fix it you should add the same listener to the button and to all of the possible panel's children recursively.
It may sound as a minor problem, but it gets complicated if the hierarachy is changing. In this case you should add this listener to the newly added component and remove it accordingly.

By the way, adding a mouseListener may considerably change the component's behaviour as I illustrated in my very first entry. So implementing a simple animation for a compound component is quite a challenging task in Swing.

Missing API

Compound components is a key part of any GUI toolkit so it is important to support them in a better way. In Swing I am missing a simple solution which would give me a chance to listen for the input events not for a single component but for a component and all its subcomponents. JLayer component added in JDK 7, can catch all the events from its children, but this is a topic for another entry.

This was an entry from the Swing in a better world series

Thanks
alexp