Component-Managed Pop-ups
Things get a bit easier in Java 5.0, using the new pop-up menu API for components. In Java 5.0, any JComponent can manage a JPopupMenu directly with the setComponentPopupMenu( ) method. JComponents can also be told to simply inherit their parent container's pop-up menu via the setInheritsPopupMenu( ) method. This combination makes it very simple to implement a context menu that should appear in many components within a container. Unfortunately, this doesn't lend itself well to our previous example (PopupColorMenu) for two reasons. First, we need to know which component the mouse was in when the pop-up was triggered and we don't get that information using this API. The pop-up handling is actually delegated to the container, not inherited. Second, not all types of components are registered to receive mouse events by default.[*] As a result, we'll create a new example that is more appropriate for a "one context menu to rule them all" app. The following example, ContextMenu, shows a TextArea and TextField that both inherit the same JPopupMenu from their JPanel container. When you select a menu item, the action is displayed in the text area.
[*] Components such as JPanel and JLabel by default do not expect to handle mouse events. When you register a listener such as MouseListener, it registers itself internally to begin processing these events. Unfortunately, at the time of this writing, using setInheritsPopupMenu( ) does not trigger this functionality. As a workaround, you could register a dummy mouse listener with these components to prompt them to expect mouse events and properly trigger context menus if you want them.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ContextMenu implements ActionListener
{
JTextArea textArea = new JTextArea( );
public ContextMenu( )
{
final JPopupMenu contextMenu = new JPopupMenu("Edit");
contextMenu.add(makeMenuItem("Save"));
contextMenu.add(makeMenuItem("Save As"));
contextMenu.add(makeMenuItem("Close"));
JFrame frame = new JFrame("ContextMenu v1.0");
JPanel panel = new JPanel( );
panel.setLayout( new BorderLayout( ) );
frame.add( panel );
panel.setComponentPopupMenu( contextMenu );
textArea.setInheritsPopupMenu( true );
panel.add( BorderLayout.CENTER, textArea );
JTextField textField = new JTextField( );
textField.setInheritsPopupMenu( true );
panel.add( BorderLayout.SOUTH, textField );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setSize(400,200);
frame.setVisible(true);
}
public void actionPerformed( ActionEvent e ) {
textArea.append( e.getActionCommand( ) +"\n" );
}
private JMenuItem makeMenuItem(String label) {
JMenuItem item = new JMenuItem(label);
item.addActionListener( this );
return item;
}
public static void main(String[] args) {
new ContextMenu( );
}
}
We've constructed our JPopupMenu as before, but this time we are not responsible for listening for mouse clicks or triggering the pop-up explicitly. Instead we use the setComponentPopupMenu( ) method to ask the JPanel to handle it for us. We use setInheritsPopupMenu( ) on both the JTextArea and JTextField so that they will both delegate pop-up trigger mouse clicks to the JPanel automatically.