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.

Java ScreenShot
Comments