Swing的JCheckBoxMenuItem组件的行为类似于我们将一个JCheckBox作为一个JMenuItem放置在菜单上。菜单项的数据模型是ToggleButtonModel,我们在第5章进行了描述。他可以使得菜单项具有选中或是未选中状态,同时显示合适的状态图标。因为数据模型是ToggleButtonModel,当JCheckBoxMenuItem位于一个ButtonGroup中时,该组中只有一个JCheckBoxMenuItem可以被选中。然而,这并不是JCheckBoxMenuItem的通常使用方法,并且很可能会迷惑用户。如果我们需要这种行为,我们可以使用JRadioButtonMenuItem,如本章稍后所述。
创建JCheckBoxMenuItem组件
JCheckBoxMenuItem有七个构造函数。这些构造函数可以允许我们初始化文本标签,图标以及初始状态。
public JCheckBoxMenuItem() JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem();
public JCheckBoxMenuItem(String text) JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem("Boy");
public JCheckBoxMenuItem(Icon icon) Icon boyIcon = new ImageIcon("boy-r.jpg"); JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(boyIcon);
public JCheckBoxMenuItem(String text, Icon icon) JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem("Boy", boyIcon);
public JCheckBoxMenuItem(String text, boolean state) JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem("Girl", true);
public JCheckBoxMenuItem(String text, Icon icon, boolean state) Icon girlIcon = new ImageIcon("girl-r.jpg"); JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem("Girl", girlIcon, true);
public JCheckBoxMenuItem(Action action) Action action = ...; JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(action);
与JCheckBox不同,图标是标签的一部分,而并不是一个单独的设备来表明某项是否被选中。如果在其构造函数中并没有传递文本标签或是图标,菜单项标签部分则会被设置其空的默认值。默认情况下,JCheckBoxMenuItem初始时未选中。
JCheckBoxMenuItem属性
JCheckBoxMenuItem的大部分属性都是由JCheckBoxMenuItem的多个超类继承来的。表6-11列出了JCheckBoxMenuItem所列出的四个属性。
JCheckBoxMenuItem属性
属性名 |
数据类型 |
访问性 |
accessibleContext |
AccessibleContext |
只读 |
selectedObjects |
Object[] |
只读 |
state |
boolean |
读写 |
UIClassID |
String |
只读 |
处理JCheckBoxMenuItem选中事件
对于JCheckBoxMenuItem而言,我们可以关联多个事件变体:
尽管我们可以监听18种没的事件类型,但是最有趣的还是ActionEvent与ItemEvent,如下所述。
使用ActionListener监听JCheckBoxMenuItem事件
将ActionListener关联到JCheckBoxMenuItem可以使得我们确定菜单何时被选中。监听器会被通知选中事件,但是并不会得到新状态的通知。要确定选中状态,我们必须获取事件源模型并查询选中状态,如下面的示例ActionListener源码所示。这个监听器会依据当前的选中状态修改复选框的文本与图标标签。
ActionListener aListener = new ActionListener() { public void actionPerformed(ActionEvent event) { Icon girlIcon = new ImageIcon("girl-r.jpg"); Icon boyIcon = new ImageIcon("boy-r.jpg"); AbstractButton aButton = (AbstractButton)event.getSource(); boolean selected = aButton.getModel().isSelected(); String newLabel; Icon newIcon; if (selected) { newLabel = "Girl"; newIcon = girlIcon; } else { newLabel = "Boy"; newIcon = boyIcon; } aButton.setText(newLabel); aButton.setIcon(newIcon); } };
使用ItemListener监听JCheckBoxMenuItem事件
如果我们使用ItemListener监听JCheckBoxMenuItem选中事件,我们并不需要查询事件源以确定选中状态,事件已经带有这些信息了。依据这个状态,我们可以进行正确的响应。使用ItemListener重新创建ActionListener的行为只需要对前面所列出的源代码进行简单的修改,如下所示:
ItemListener iListener = new ItemListener() { public void itemStateChanged(ItemEvent event) { Icon girlIcon = new ImageIcon("girl-r.jpg"); Icon boyIcon = new ImageIcon("boy-r.jpg"); AbstractButton aButton = (AbstractButton)event.getSource(); int state = event.getStateChange(); String newLabel; Icon newIcon; if (state == ItemEvent.SELECTED) { newLabel = "Girl"; newIcon = girlIcon; } else { newLabel = "Boy"; newIcon = boyIcon; } aButton.setText(newLabel); aButton.setIcon(newIcon); } };
自定义JCheckBoxMenuItem观感
图6-3显示了预安装的观感类型集合下JCheckBoxMenuItem的外观。
表6-12列出了JCheckBoxMenuItem的UIResource相关的属性。JCheckBoxMenuItem组件具有19个不同的属性。
JCheckBoxMenuItem UIResource元素
属性字符串 |
对象类型 |
CheckBoxMenuItem.acceleratorFont |
Font |
CheckBoxMenuItem.acceleratorForeground |
Color |
CheckBoxMenuItem.acceleratorSelectionForeground |
Color |
CheckBoxMenuItem.actionMap |
ActionMap |
CheckBoxMenuItem.arrowIcon |
Icon |
CheckBoxMenuItem.background |
Color |
CheckBoxMenuItem.border |
Border |
CheckBoxMenuItem.borderPainted |
Boolean |
CheckBoxMenuItem.checkIcon |
Icon |
CheckBoxMenuItem.commandSound |
String |
CheckBoxMenuItem.disabledForeground |
Color |
CheckBoxMenuItem.font |
Font |
CheckBoxMenuItem.foreground |
Color |
CheckBoxMenuItem.gradient |
List |
CheckBoxMenuItem.margin |
Insets |
CheckBoxMenuItem.opaue |
Boolean |
CheckBoxMenuItem.selectionBackground |
Color |
CheckBoxMenuItem.selectionForeground |
Color |
CheckBoxMenuItemUI |
String |
与CheckboxMenuItem.checkIcon属性键值相关联的Icon是显示在JCheckBoxMenuItem上的图标。如果我们不喜欢默认图标,我们可以使用下面的代码行进行修改,在这里假定已经定义并创建了新图标:
UIManager.put("CheckBoxMenuItem.checkIcon", someIcon);
为了使得新图标可以显示合适的选中图像,Icon实现必须其paintIcon()方法内检测关联的菜单组件状态。第4章所创建的DiamondIcon对于这个图标并不起作用,因为他并不检测其状态组件。相反,状态是在构造是确定的。列表6-4列出了一个可以使用的图标类。
package net.ariel.ch06;
import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Polygon;
import javax.swing.AbstractButton; import javax.swing.Icon;
public class DiamondAbstractButtonStateIcon implements Icon { private final int width = 10; private final int height = 10; private Color color; private Polygon polygon;
public DiamondAbstractButtonStateIcon(Color color) { this.color = color; initPolygon(); }
private void initPolygon() { polygon = new Polygon(); int halfWidth = width/2; int halfHeight = height/2; polygon.addPoint(0, halfHeight); polygon.addPoint(halfWidth, 0); polygon.addPoint(width, halfHeight); polygon.addPoint(halfWidth, height); } @Override public int getIconHeight() { // TODO Auto-generated method stub return height; }
@Override public int getIconWidth() { // TODO Auto-generated method stub return height; }
@Override public void paintIcon(Component component, Graphics g, int x, int y) { // TODO Auto-generated method stub boolean selected = false; g.setColor(color); g.translate(x, y); if(component instanceof AbstractButton) { AbstractButton abstractButton = (AbstractButton)component; selected = abstractButton.isSelected(); } if(selected) { g.fillPolygon(polygon); } else { g.drawPolygon(polygon); } g.translate(-x, -y); } }
JRadioButtonMenuItem组件具有所有的Swing组件中最长的名字。其作用类似于JRadioButton,但是位于菜单中。当与其他的JRadioButtonMenuItem组件共同放在一个ButtonGroup中时,每次只有一个组件可以被选中。与JRadioButton类似,JRadioButtonMenuItem的按钮模型是JToggleButton.ToggleButtonModel。
创建JRadioButtonMenuItem组件
JRadioButtonMenuItem具有七个构造函数。这些构造函数允许我们初始化文本标签,图标以及初始状态。
public JCheckBoxMenuItem() JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(); public JCheckBoxMenuItem(String text) JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem("Boy"); public JCheckBoxMenuItem(Icon icon) Icon boyIcon = new ImageIcon("boy-r.jpg"); JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(boyIcon); public JCheckBoxMenuItem(String text, Icon icon) JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem("Boy", boyIcon); public JCheckBoxMenuItem(String text, boolean state) JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem("Girl", true); public JCheckBoxMenuItem(String text, Icon icon, boolean state) Icon girlIcon = new ImageIcon("girl-r.jpg"); JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem("Girl", girlIcon, true); public JCheckBoxMenuItem(Action action) Action action = ...; JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(action);
与JCheckBoxMenuItem组件类似,JRadioButtonMenuItem的图标也是标签的一部分。这与JRadioButton不同,在JRadioButton中图标可以表明单选按钮是否被选中。如果在构造函数中并没有传递文本标签或是图标,则项目标签部分则为空。在默认情况下,JRadioButtonMenuItem初始时未选中。如果我们创建一个选中的JRadioButtonMenuItem并将其添加到ButtonGroup中,如果在按钮组中已有一个被选中的项目时,则按钮组会取消新创建的菜单项的选中状态。
处理JRadioButtonMenuItem的选中事件
JRadioButtonMenuItem共享与JCheckBoxMenuItem相同的18个不同的事件/监听器对。要监听选中事件,关联ActionListener是通常的方法。另外,我们也许希望将相同的监听器关联到ButtonGroup中所有的JRadioButtonMenuItem对象之上,毕竟他们由于某种原因分为一组。如果我们使用相同的监听器,监听器可以依据当前的选中而执行某些通常的操作。在其他情况下,如图6-1所示,JRadioButtonMenuItem选项的选中并不进行任何操作。
配置JRadioButtonMenuItem属性
与JCheckBoxMenuItem类似,大部分的JRadioButtonMenuItem属性都是继承的。表6-13中的两个属性覆盖了超类的行为。
JRadioButtonMenuItem属性
属性名 |
数据类型 |
访问性 |
accessibleContext |
AccessibleContext |
只读 |
UIClassID |
String |
只读 |
自定义JRadioButtonMenuItem观感
图6-3显示了预安装的观感类型集合下的JRadioButtonMenuItem的外观。
表6-14显示了JRadioButtonMenuItem的UIResource相关的属性集合。对于JRadioButtonMenuItem组件而言,共有19个不同的属性。
JRadioButtonMenuItem UIResource元素
属性字符串 |
对象类型 |
RadioButtonMenuItem.acceleratorFont |
Font |
RadioButtonMenuItem.acceleratorForeground |
Color |
RadioButtonMenuItem.acceleratorSelectionForeground |
Color |
RadioButtonMenuItem.actionMap |
ActionMap |
RadioButtonMenuItem.arrowIcon |
Icon |
RadioButtonMenuItem.background |
Color |
RadioButtonMenuItem.border |
Border |
RadioButtonMenuItem.borderPainted |
Boolean |
RadioButtonMenuItem.checkIcon |
Icon |
RadioButtonMenuItem.commandSound |
String |
RadioButtonMenuItem.disabledForeground |
Color |
RadioButtonMenuItem.font |
Font |
RadioButtonMenuItem.foreground |
Color |
RadioButtonMenuItem.gradient |
List |
RadioButtonMenuItem.margin |
Insets |
RadioButtonMenuItem.opaque |
Boolean |
RadioButtonMenuItem.selectionBackground |
Color |
RadioButtonMenuItem.selectionForeground |
Color |
RadioButtonMenuItemUI |
String |
完整的JRadioButtonMenuItem使用示例
为了助于我们理解JRadioButtonMenuItem的使用,列表6-5中的程序演示了如何将所有的内容组合在一起,包括监听菜单上的所有菜单项的选中,使用ActionListener或是ItemListener。程序的输出如图6-8所示。
/** * */ package net.ariel.ch06;
import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent;
import javax.swing.AbstractButton; import javax.swing.ButtonGroup; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JRadioButtonMenuItem; /** * @author mylxiaoyi * */ public class RadioButtonSample { static Icon threeIcon = new ImageIcon("3.gif"); static Icon fourIcon = new ImageIcon("4.gif"); static Icon fiveIcon = new ImageIcon("5.gif"); static Icon sixIcon = new ImageIcon("6.gif");
public static class ButtonActionListener implements ActionListener { public void actionPerformed(ActionEvent event) { AbstractButton aButton = (AbstractButton)event.getSource(); boolean selected = aButton.getModel().isSelected(); System.out.println(event.getActionCommand()+" - selected? "+selected); } }
public static class ButtonItemListener implements ItemListener { public void itemStateChanged(ItemEvent event) { AbstractButton aButton = (AbstractButton)event.getSource(); int state = event.getStateChange(); String selected = ((state == event.SELECTED)?"selected":"not selected"); System.out.println(aButton.getText()+" - selected? "+selected); } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable runner = new Runnable() { public void run() { final ActionListener actionListener = new ButtonActionListener(); final ItemListener itemListener = new ButtonItemListener(); JFrame frame = new JFrame("Radio Menu Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JMenuBar menuBar = new JMenuBar(); JMenu menu = new JMenu("Menu"); ButtonGroup buttonGroup = new ButtonGroup(); menu.setMnemonic(KeyEvent.VK_M); JRadioButtonMenuItem emptyMenuItem = new JRadioButtonMenuItem(); emptyMenuItem.setActionCommand("Empty"); emptyMenuItem.addActionListener(actionListener); buttonGroup.add(emptyMenuItem); menu.add(emptyMenuItem); JRadioButtonMenuItem oneMenuItem = new JRadioButtonMenuItem("Partridge"); oneMenuItem.addActionListener(actionListener); buttonGroup.add(oneMenuItem); menu.add(oneMenuItem); JRadioButtonMenuItem twoMenuItem = new JRadioButtonMenuItem("Turtle Dove", true); twoMenuItem.addActionListener(actionListener); buttonGroup.add(twoMenuItem); menu.add(twoMenuItem); JRadioButtonMenuItem threeMenuItem = new JRadioButtonMenuItem("French Hens", threeIcon); threeMenuItem.addItemListener(itemListener); buttonGroup.add(threeMenuItem); menu.add(threeMenuItem); JRadioButtonMenuItem fourMenuItem = new JRadioButtonMenuItem("Calling Birds", fourIcon, true); fourMenuItem.addActionListener(actionListener); buttonGroup.add(fourMenuItem); menu.add(fourMenuItem); JRadioButtonMenuItem fiveMenuItem = new JRadioButtonMenuItem(fiveIcon); fiveMenuItem.addActionListener(actionListener); fiveMenuItem.setActionCommand("Rings"); buttonGroup.add(fiveMenuItem); menu.add(fiveMenuItem); JRadioButtonMenuItem sixMenuItem = new JRadioButtonMenuItem(sixIcon, true); sixMenuItem.addActionListener(actionListener); sixMenuItem.setActionCommand("Geese"); buttonGroup.add(sixMenuItem); menu.add(sixMenuItem); menuBar.add(menu); frame.setJMenuBar(menuBar); frame.setSize(350, 250); frame.setVisible(true); } }; EventQueue.invokeLater(runner); } }
所有可选择的菜单组件的共同之处在于他们都实现了MenuElement接口。JSeparator没有实现这个接口,但这并没有关系,因为他并不是可选择的。MenuElement接口的目的就是使得MenuSelectionManager在用户在程序菜单结构周围移动时通知不同的菜单元素。
如下面的接口定义所示,MenuElement接口由五个方法构成:
public interface MenuElement { public Component getComponent(); public MenuElement[] getSubElements(); public void menuSelectionChanged(boolean isInclude); public void processKeyEvent(KeyEvent event, MenuElement path[], MenuSelectionManager mgr); public void processMouseEvent(MouseEvent event, MenuElement path[], MenuSelectionManager mgr); }
getComponent()方法返回菜单的渲染组件。这通常是菜单组件本身,尽管这并不是必须的。getSubElements()方法返回元素内所包含的菜单元素数组。如果这个菜单元素并不是子菜单的顶部,这个方法会返回一个零长度的MenuElement对象数组,而不是null。
当菜单项被放入菜单选择管理器的选择路径或是由菜单选择管理器的选择路径移除时会调用menuSelectionChanged()方法。
processKeyEvent()与processMouseEvent()两个方法用于处理菜单上所生成的按键事件或是鼠标事件。我们的菜单项如何处理事件依赖于组件所支持的内容。例如,除非我们支持快捷键,我们可能希望只有当我们的菜单项位于当前的选择路径时才响应按键事件。
为了演示MenuElement接口,列表6-6创建了一个名为JToggleButtonMenuItem的新菜单组件。这个组件的行为类似于JToggleButton,尽管他可以放在菜单上。保证当菜单项被选中时菜单响应并且当位于当前的选择路径时组件可以进行不同显示是很重要的。
注意:尽管我们可以在菜单中添加任何组件,如果组件没有实现MenuElement接口,则当鼠标略过组件或是当组件被选中时,该组件并不能进行正确的响应。
/** * */ package net.ariel.ch06;
import java.awt.Color; import java.awt.Component; import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent;
import javax.swing.Action; import javax.swing.ButtonModel; import javax.swing.JToggleButton; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.event.MouseInputListener; /** * @author mylxiaoyi * */ public class JToggleButtonMenuItem extends JToggleButton implements MenuElement {
Color savedForeground = null; private static MenuElement NO_SUB_ELEMENTS[] = new MenuElement[0];
public JToggleButtonMenuItem() {
init();
}
public JToggleButtonMenuItem(String label) { super(label); init(); }
public JToggleButtonMenuItem(Action action) { super(action); init(); }
private void init() { updateUI(); setRequestFocusEnabled(false); // Borrows heavily from BasicMenuUI MouseInputListener mouseInputListener = new MouseInputListener() { // If mouse release over this menu item, activate it public void mouseReleased(MouseEvent event) { MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager(); Point point = event.getPoint(); if((point.x >= 0) && (point.x < getWidth()) && (point.y >= 0) && (point.y < getHeight())) { menuSelectionManager.clearSelectedPath(); // Component automatically handles "selection" at this point // doClick(0); // not necessary } else { menuSelectionManager.processMouseEvent(event); } }
@Override public void mouseClicked(MouseEvent event) { // TODO Auto-generated method stub } // if mouse moves over menu item, add to selection path, so it becomes armed @Override public void mouseEntered(MouseEvent event) { // TODO Auto-generated method stub MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager(); menuSelectionManager.setSelectedPath(getPath()); } // when mouse moves away from menu item, disarm it and select something else @Override public void mouseExited(MouseEvent event) { // TODO Auto-generated method stub MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager(); MenuElement path[] = menuSelectionManager.getSelectedPath(); if(path.length > 1) { MenuElement[] newPath = new MenuElement[path.length-1]; for(int i=0, c=path.length-1; i @Override public void mousePressed(MouseEvent event) { // TODO Auto-generated method stub } // pass along drag events @Override public void mouseDragged(MouseEvent event) { // TODO Auto-generated method stub MenuSelectionManager.defaultManager().processMouseEvent(event); } @Override public void mouseMoved(MouseEvent event) { // TODO Auto-generated method stub } }; addMouseListener(mouseInputListener); addMouseMotionListener(mouseInputListener); } /* (non-Javadoc) * @see javax.swing.MenuElement#getComponent() */ @Override public Component getComponent() { // TODO Auto-generated method stub return this; } /* (non-Javadoc) * @see javax.swing.MenuElement#getSubElements() */ @Override public MenuElement[] getSubElements() { // TODO Auto-generated method stub return NO_SUB_ELEMENTS; } /* (non-Javadoc) * @see javax.swing.MenuElement#menuSelectionChanged(boolean) */ @Override public void menuSelectionChanged(boolean isIncluded) { // TODO Auto-generated method stub ButtonModel model = getModel(); // only change armed state if different if(model.isArmed() != isIncluded) { model.setArmed(isIncluded); } if(isIncluded) { savedForeground = getForeground(); if(!savedForeground.equals(Color.BLUE)) { setForeground(Color.BLUE); } else { // in case foreground blue, use something different setForeground(Color.BLUE); } } else { setForeground(savedForeground); // if null, get foreground from installed look and feel if(savedForeground == null) { updateUI(); } } } /* (non-Javadoc) * @see javax.swing.MenuElement#processKeyEvent(java.awt.event.KeyEvent, javax.swing.MenuElement[], javax.swing.MenuSelectionManager) */ @Override public void processKeyEvent(KeyEvent event, MenuElement[] path, MenuSelectionManager manager) { // TODO Auto-generated method stub // if user presses space while menu item armed, select it if(getModel().isArmed()) { int keyChar = event.getKeyChar(); if(keyChar == KeyEvent.VK_SPACE) { manager.clearSelectedPath(); System.out.println("Selected: JToggleButtonMenuItem, by KeyEvent"); doClick(0); // inheried from AbstractButton } } } /* (non-Javadoc) * @see javax.swing.MenuElement#processMouseEvent(java.awt.event.MouseEvent, javax.swing.MenuElement[], javax.swing.MenuSelectionManager) */ @Override public void processMouseEvent(MouseEvent event, MenuElement[] path, MenuSelectionManager manager) { // TODO Auto-generated method stub // for when mose dragged over menu and button released if(event.getID() == MouseEvent.MOUSE_RELEASED) { manager.clearSelectedPath(); System.out.println("Selected: JToggleButtonMenuItem, by MouseEvent"); doClick(0); } } // borrows heavily from BasicMenuItemUI.getPath() private MenuElement[] getPath() { MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager(); MenuElement oldPath[] = menuSelectionManager.getSelectedPath(); MenuElement newPath[]; int oldPathLength = oldPath.length; if(oldPathLength == 0) return new MenuElement[0]; Component parent = getParent(); if(oldPath[oldPathLength-1].getComponent() == parent) { // going deeper under the parent menu newPath = new MenuElement[oldPathLength+1]; System.arraycopy(oldPath, 0, newPath, 0, oldPathLength); newPath[oldPathLength] = this; } else { // sibling/child menu item currently selected int newPathPosition; for(newPathPosition = oldPath.length-1; newPathPosition >= 0; newPathPosition--) { if(oldPath[newPathPosition].getComponent() == parent) { break; } } newPath = new MenuElement[newPathPosition+2]; System.arraycopy(oldPath, 0, newPath, 0, newPathPosition+1); newPath[newPathPosition+1] = this; } return newPath; } }
一旦我们创建了JToggleButtonMenuItem类,我们就可以像使用其他的菜单项一样来使用:
JToggleButtonMenuItem toggleItem = new JToggleButtonMenuItem("Balloon Help"); editMenu.add(toggleItem);