ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Java Swing: Menus and Toolbars, Part 6
Pages: 1, 2

Enforcing Mutual Exclusion

The following program shows how to implement the mutually exclusive nature of radio button menu items:



//  RadioButtonMenuItemExample.java
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class RadioButtonMenuItemExample extends JPanel {

    public JTextPane pane;
    public JMenuBar menuBar;
    public JToolBar toolBar;

    public RadioButtonMenuItemExample(  ) {
        menuBar = new JMenuBar(  );
        JMenu justifyMenu = new JMenu("Justify");
        ActionListener actionPrinter = new ActionListener(  ) {
            public void actionPerformed(ActionEvent e) {
                try { pane.getStyledDocument(  ).insertString(0 ,
                      "Action ["+e.getActionCommand(  )+"] 
					     performed!\n", null);
                } catch (Exception ex) { ex.printStackTrace(  ); }
            }
        };
        JRadioButtonMenuItem leftJustify = new
               JRadioButtonMenuItem("Left", new ImageIcon("left.gif"));
        leftJustify.setHorizontalTextPosition(JMenuItem.RIGHT);
        leftJustify.setAccelerator(KeyStroke.getKeyStroke('L',
                        Toolkit.getDefaultToolkit(  ).getMenuShortcutKeyMask(  )));
        leftJustify.addActionListener(actionPrinter);
        JRadioButtonMenuItem rightJustify = new
               JRadioButtonMenuItem("Right", new ImageIcon("right.gif"));
        rightJustify.setHorizontalTextPosition(JMenuItem.RIGHT);
        rightJustify.setAccelerator(KeyStroke.getKeyStroke('R',
                        Toolkit.getDefaultToolkit(  ).getMenuShortcutKeyMask(  )));
        rightJustify.addActionListener(actionPrinter);
        JRadioButtonMenuItem centerJustify = new
               JRadioButtonMenuItem("Center", new ImageIcon("center.gif"));
        centerJustify.setHorizontalTextPosition(JMenuItem.RIGHT);
        centerJustify.setAccelerator(KeyStroke.getKeyStroke('M',
                        Toolkit.getDefaultToolkit(  ).getMenuShortcutKeyMask(  )));
        centerJustify.addActionListener(actionPrinter);
        JRadioButtonMenuItem fullJustify = new
               JRadioButtonMenuItem("Full", new ImageIcon("full.gif"));
        fullJustify.setHorizontalTextPosition(JMenuItem.RIGHT);
        fullJustify.setAccelerator(KeyStroke.getKeyStroke('F',
                        Toolkit.getDefaultToolkit(  ).getMenuShortcutKeyMask(  )));
        fullJustify.addActionListener(actionPrinter);

        ButtonGroup group = new ButtonGroup(  );
        group.add(leftJustify);
        group.add(rightJustify);
        group.add(centerJustify);
        group.add(fullJustify);

        justifyMenu.add(leftJustify);
        justifyMenu.add(rightJustify);
        justifyMenu.add(centerJustify);
        justifyMenu.add(fullJustify);

        menuBar.add(justifyMenu);
        menuBar.setBorder(new BevelBorder(BevelBorder.RAISED));
    }
    public static void main(String s[ ]) {

        RadioButtonMenuItemExample example = new
                                        RadioButtonMenuItemExample(  );
        example.pane = new JTextPane(  );
        example.pane.setPreferredSize(new Dimension(250, 250));
        example.pane.setBorder(new BevelBorder(BevelBorder.LOWERED));

        JFrame frame = new JFrame("Menu Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(example.menuBar);
        frame.getContentPane(  ).add(example.pane, BorderLayout.CENTER);
        frame.pack(  );
        frame.setVisible(true);
    }
}

Figure 14-17 shows the result. We use a ButtonGroup object to make our JRadioButtonMenuItems mutually exclusive. Selecting any of the menu items deselects the others. Since text justification is mutually exclusive, this example shows how you would implement a real justification menu.

Figure 14-17. An example of radio button menu items

The JSeparator Class

You may have noticed that both JMenu and JPopupMenu contain addSeparator( ) methods to add separators to menus. In doing so, each class instantiates a JSeparator object and positions it in the menu. However, JSeparator exists as a component unto itself outside of menus, and, because it extends JComponent, it can be positioned inside a container like any other Swing component. JSeparator is a simple component that provides separation between logical groups of menu items. In some L&Fs it shows up as a horizontal line drawn across its entire width; in others, it is invisible and just adds a little extra space between elements. It has no model, only a delegate.

Properties

Table 14-11 shows the properties of JSeparator.

Table 14-11: JSeparator properties

Property

Data type

get

is

set

Default value

accessibleContexto

AccessibleContext

·

 

 

JSeparator.accessibleJSeparator( )

orientation

int

·

 

·

SwingConstants.HORIZONTAL

UIb

SeparatorUI

·

 

·

From L&F

UIClassIDo

String

·

 

 

"SeparatorUI"

bbound, ooverridden
See also properties from the JComponent class (Table 3-6).


Constructor

JSeparator(  )
JSeparator(int orientation)

Create a separator. By default, this separator is horizontal; if you specify an orientation, it should be either SwingConstants.HORIZONTAL or SwingConstants.VERTICAL.

Miscellaneous

public void updateUI(  )

Force the current UI manager to reset and repaint the delegate for the component, thus updating the component's L&F.

Using a Separator Outside of a Menu

We've already seen how a separator can be used in menus to highlight the grouping of menu items. However, separators are components in themselves and can be used for a variety of tasks. Here is a program that adds a separator between a series of buttons:

// SeparatorExample.java
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class SeparatorExample extends JPanel {

    public SeparatorExample(  ) {
        super(true);

        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        Box box1 = new Box(BoxLayout.X_AXIS);
        Box box2 = new Box(BoxLayout.X_AXIS);
        Box box3 = new Box(BoxLayout.X_AXIS);

        box1.add(new JButton("Press Me"));
        box1.add(new JButton("No Me!"));
        box1.add(new JButton("Ignore Them!"));
        box2.add(new JSeparator(  ));
        box3.add(new JButton("I'm the Button!"));
        box3.add(new JButton("It's me!"));
        box3.add(new JButton("Go Away!"));

        add(box1);
        add(box2);
        add(box3);
    }
    public static void main(String s[ ]) {

        SeparatorExample example = new SeparatorExample(  );

        JFrame frame = new JFrame("Separator Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(example);
        frame.pack(  );
        frame.setVisible(true);
    }
}

This code yields the interface shown in Figure 14-18. Note that on platforms where separators are invisible, they are difficult or impossible to notice when used in this unorthodox way. (Even in this example, in which the separator has a visual representation, it's pretty hard to see!)

Figure 14-18. A standalone separator between two groups of buttons

The MenuElement Interface

As we saw in the previous examples, one nice feature of Swing menus is that we are not constrained to using text for menu items. However, the possibilities don't have to stop with icons, either. In fact, with a little work you can create or extend any Java component to serve as a menu item. There is one catch: your new menu item must implement the MenuElement interface. Swing declares five methods in the MenuElement interface; these methods are called by Swing's internal MenuSelectionManager when various actions take place.

Why is this necessary? Let's look at the traditional menu item, such as the Paste item in the Edit menu. When the user raises the Edit menu, and the mouse passes over the Paste menu item, the menu item typically highlights itself, usually by changing color. This tells the user that releasing (or clicking, depending on the L&F) the mouse button chooses the Paste option. When the mouse leaves the menu item, it returns to its normal color. However, what if we wanted to make the text bold instead of highlighting it? What if we wanted to substitute another icon image in the menu item when the mouse passed over it? By calling the methods of this interface, menus allow menu items to define their own unique behavior.

Methods

public void processMouseEvent(MouseEvent event,MenuElement path[ ], 
     MenuSelectionManager manager)

This method handles events triggered by the mouse. In addition to the MouseEvent, the current path of selected menu elements is provided, as well as a reference to the current menu selection manager. You can take whatever action you feel is necessary with this method.

public void processKeyEvent(KeyEvent event, MenuElement path[ ], 
     MenuSelectionManager manager)

This method handles events triggered by keystrokes. In addition to the KeyEvent, the current path of selected menu elements is provided as well as a reference to the current menu selection manager. You can take whatever action you feel is necessary in this method.

public void menuSelectionChanged(boolean isIncluded)

Called when the menu element is added or removed from the current target menu.

public MenuElement[ ] getSubElements(  )

Return an array of subelements for the target MenuElement. This is needed in the event that a particular menu element has a submenu.

public Component getComponent(  )

Return a reference to the component responsible for painting the menu item.

Making Arbitrary Components into Menu Elements

It is relatively easy to convert any Swing component into a menu element and drop it in a menu. Here is a program that places a JSlider inside a pop-up menu and uses it as a hidden control for an underlying component.

//  MenuElementExample.java
//
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;

public class MenuElementExample extends JPanel {

    public JPopupMenu popup;
    SliderMenuItem slider;
    int theValue = 0;

    public MenuElementExample(  ) {

        popup = new JPopupMenu(  );
        slider = new SliderMenuItem(  );

        popup.add(slider);
        popup.add(new JSeparator(  ));

        JMenuItem ticks = new JCheckBoxMenuItem("Slider Tick Marks");
        ticks.addActionListener(new ActionListener(  ) {
            public void actionPerformed(ActionEvent event) {
                slider.setPaintTicks(!slider.getPaintTicks(  ));
            }
        });
        JMenuItem labels = new JCheckBoxMenuItem("Slider Labels");
        labels.addActionListener(new ActionListener(  ) {
            public void actionPerformed(ActionEvent event) {
                slider.setPaintLabels(!slider.getPaintLabels(  ));
            }
        });
        popup.add(ticks);
        popup.add(labels);
        popup.addPopupMenuListener(new PopupPrintListener(  ));

        addMouseListener(new MousePopupListener(  ));
    }
    // Inner class to check whether mouse events are the pop-up trigger
    class MousePopupListener extends MouseAdapter {
        public void mousePressed(MouseEvent e) { checkPopup(e); }
        public void mouseClicked(MouseEvent e) { checkPopup(e); }
        public void mouseReleased(MouseEvent e) { checkPopup(e); }
        private void checkPopup(MouseEvent e) {
            if (e.isPopupTrigger(  )) {
                popup.show(MenuElementExample.this, e.getX(  ), e.getY(  ));
            }
        }
    }
    // Inner class to print information in response to pop-up events
    class PopupPrintListener implements PopupMenuListener {
        public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
            theValue = slider.getValue(  );
            System.out.println("The value is now " + theValue);
        }
        public void popupMenuCanceled(PopupMenuEvent e) {
            System.out.println("Popup menu is hidden!");
        }
    }
  
    public static void main(String s[ ]) {
        JFrame frame = new JFrame("Menu Element Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(new MenuElementExample(  ));
        frame.setSize(300, 300);
        frame.setVisible(true);
    }
    // Inner class that defines our special slider menu item
    class SliderMenuItem extends JSlider implements MenuElement {

        public SliderMenuItem(  ) {
            setBorder(new CompoundBorder(new TitledBorder("Control"),
                                  new EmptyBorder(10, 10, 10, 10)));

            setMajorTickSpacing(20);
            setMinorTickSpacing(10);
        }
        public void processMouseEvent(MouseEvent e, MenuElement path[ ],
                                      MenuSelectionManager manager) {}
        public void processKeyEvent(KeyEvent e, MenuElement path[ ],
                                    MenuSelectionManager manager) {}
        public void menuSelectionChanged(boolean isIncluded) {}
        public MenuElement[ ] getSubElements(  ) {return new MenuElement[0];}
        public Component getComponent(  ) {return this;}
    }
}

As with our previous pop-up example, PopupMenuExample, we implement MouseListener and check incoming mouse events to see whether to show the pop up. The inner class SliderMenuItem implements the MenuElement interface, and is the focus of our example. In this case, it's fairly easy. Our menu slider never has subelements, doesn't have a concept of a selection, and doesn't need to do anything special with mouse or key events.

The interface resulting from our example is shown in Figure 14-19. We provide a JSlider object, a separator, and two JCheckBoxMenuItem objects, which control the state of the slider. The slider is also surrounded by a titled border. When the user adjusts the slider and dismisses the pop up, we print the current value of the slider to the standard output. With a little bit of imagination, you can do just about anything with a pop-up menu. Of course, if it's something unexpected, you should carefully consider whether it is likely to confuse or confound your users.

Figure 14-19. A JSlider masquerading as a pop-up menu element in two L&Fs

In the next installment, learn about Toolbars.


Return to ONJava.com.