这是一个具有JMenu 的自定义弹出窗口效果的组合。实际的弹出窗口被隐藏,并在适当的时候显示第二个弹出窗口。
选择JMenuItem 后,组合中将仅填充一项,以面包屑格式显示。
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.basic.*;
import javax.swing.plaf.metal.*;
public class JMenuComboBoxDemo implements Runnable
{
private Map<String, String[]> menuData;
private JComboBox<String> combo;
private AbstractButton arrowButton;
private JPopupMenu popupMenu;
private List<String> flattenedData;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new JMenuComboBoxDemo());
}
public JMenuComboBoxDemo()
{
menuData = new HashMap<String, String[]>();
menuData.put("Colors", new String[]{"Black", "Blue"});
menuData.put("Flavors", new String[]{"Lemon", "Lime"});
popupMenu = new JPopupMenu();
popupMenu.setBorder(new MatteBorder(1, 1, 1, 1, Color.DARK_GRAY));
List<String> categories = new ArrayList<String>(menuData.keySet());
Collections.sort(categories);
// copy of the menuData, flattened into a List
flattenedData = new ArrayList<String>();
for (String category : categories)
{
JMenu menu = new JMenu(category);
for (String itemName : menuData.get(category))
{
menu.add(createMenuItem(itemName));
flattenedData.add(category + " > " + itemName);
}
popupMenu.add(menu);
}
combo = new JComboBox<String>();
combo.setPrototypeDisplayValue("12345678901234567890");
combo.setUI(new EmptyComboBoxUI());
for (Component comp : combo.getComponents())
{
if (comp instanceof AbstractButton)
{
arrowButton = (AbstractButton) comp;
}
}
arrowButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
setPopupVisible(! popupMenu.isVisible());
}
});
combo.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
setPopupVisible(! popupMenu.isVisible());
}
});
}
public void run()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = frame.getContentPane();
c.setLayout(new FlowLayout());
c.add(new JLabel("Options"));
c.add(combo);
frame.setSize(300, 200);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
/*
* Toggle the visibility of the custom popup.
*/
private void setPopupVisible(boolean visible)
{
if (visible)
{
popupMenu.show(combo, 0, combo.getSize().height);
}
else
{
popupMenu.setVisible(false);
}
}
/*
* Create a JMenuItem whose listener will display
* the item in the combo.
*/
private JMenuItem createMenuItem(final String name)
{
JMenuItem item = new JMenuItem(name);
item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
setComboSelection(name);
}
});
return item;
}
/*
* Search for the given name in the flattened list of menu items.
* If found, add that item to the combo and select it.
*/
private void setComboSelection(String name)
{
Vector<String> items = new Vector<String>();
for (String item : flattenedData)
{
/*
* We're cheating here: if two items have the same name
* (Fruit->Orange and Color->Orange, for example)
* the wrong one may get selected. This should be more sophisticated
* (left as an exercise to the reader)
*/
if (item.endsWith(name))
{
items.add(item);
break;
}
}
combo.setModel(new DefaultComboBoxModel<String>(items));
if (items.size() == 1)
{
combo.setSelectedIndex(0);
}
}
/*
* Prevents the default popup from being displayed
*/
class EmptyComboBoxUI extends MetalComboBoxUI
{
@Override
protected ComboPopup createPopup()
{
BasicComboPopup thePopup = (BasicComboPopup) super.createPopup();
thePopup.setPreferredSize(new Dimension(0,0)); // oh, the horror!
return thePopup;
}
}
}