问题
Javadoc for JPopupMenu constructor says the following:
JPopupMenu
public JPopupMenu(String label)
Constructs a JPopupMenu with the specified title. Parameters: label - the string that a UI **may** use to display as a title for the popup menu.
Key word being "may". Evidently in the default UI, such titles are ignored when creating a popup menu. I very much want such titles in some of my popup menus to be used regardless of whether or not the L&F thinks I should. I can't find the hook to make it so. Evidently, this is buried deep in the UI code somewhere. Is there a way to override this default?
Failing that, I have tried adding a disabled menu item as the first item of the menu. Trouble with that is then I lose control of its rendering, and it renders in the "greyed out" style instead of appearing as the important title. If I don't disable it, then it renders as I want, but is selectable, which a title would not be.
So bottom line, how do I either force the UI to display my title, or failing that, how do I add a non-selectable menu item at the top of the menu that I have full rendering control over?
回答1:
I had similar problem (I mean the original question). I solved it this way:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
public class LabeledPopupMenu extends JPopupMenu
{
private String originalLabelText = null;
private final JLabel label;
private static String replaceHTMLEntities(String text)
{
if (-1 != text.indexOf("<") ||
-1 != text.indexOf(">") ||
-1 != text.indexOf("&"))
{
text = text.replaceAll("&", "&");
text = text.replaceAll("<", "<");
text = text.replaceAll(">", ">");
}
return text;
}
public LabeledPopupMenu()
{
super();
this.label = null;
}
public LabeledPopupMenu(String label)
{
super();
originalLabelText = label;
this.label = new JLabel("<html><b>" +
replaceHTMLEntities(label) + "</b></html>");
this.label.setHorizontalAlignment(SwingConstants.CENTER);
add(this.label);
addSeparator();
}
@Override public void setLabel(String text)
{
if (null == label) return;
originalLabelText = text;
label.setText("<html><b>" +
replaceHTMLEntities(text) +
"</b></html>");
}
@Override public String getLabel()
{
return originalLabelText;
}
}
I have tested it ony on Mac with default L&F, but it worked for me:
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(100, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(100, 100);
frame.setVisible(true);
LabeledPopupMenu myPopup = new LabeledPopupMenu("Say & <something>");
myPopup.add(new JMenuItem("Sample item"));
myPopup.show(frame, 50, 50);
}
回答2:
Wasn't even aware of that feature :-)
Digging a bit, it turns out that MotifLookAndFeel is the only of the core LAFs which support a title in the popup. It's realized by a custom border. Which you can do as well:
JPopupMenu popup = new JPopupMenu("My Label");
popup.add("dummy menu item");
Border titleUnderline = BorderFactory.createMatteBorder(1, 0, 0, 0, popup.getForeground());
TitledBorder labelBorder = BorderFactory.createTitledBorder(
titleUnderline, popup.getLabel(),
TitledBorder.CENTER, TitledBorder.ABOVE_TOP, popup.getFont(), popup.getForeground());
popup.setBorder(BorderFactory.createCompoundBorder(popup.getBorder(),
labelBorder));
JComponent comp = new JPanel();
comp.setComponentPopupMenu(popup);
Note: as far as I can see, there is no safe way to detect whether or not the LAF handles the title itself (which would result in doubling it)
回答3:
JPopup is very strange Container, didn't work me
1) public JPopupMenu(String label)
2) didn't work me alignment for JLabel, please maybe somebody can test text justify by using Html
3) not possible shows JComboBox dropdown popup is same time with JPopup (doesn't matter if is JPopup light or heavyweight)
4) and another (not important for basic Swing) tested Java5 and 6 with various LaF

import java.awt.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.event.*;
import javax.swing.plaf.*;
import org.pushingpixels.substance.api.skin.SubstanceOfficeSilver2007LookAndFeel;
class MyPopupMenuListener implements PopupMenuListener {
public void popupMenuCanceled(PopupMenuEvent popupMenuEvent) {
System.out.println("Canceled");
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent popupMenuEvent) {
System.out.println("Becoming Invisible");
}
public void popupMenuWillBecomeVisible(PopupMenuEvent popupMenuEvent) {
System.out.println("Becoming Visible");
}
}
public class PopupMenuListenerDemo {
public static void main(final String args[]) {
final JFrame frame = new JFrame("PopupSample Example");
/*SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(new SubstanceOfficeSilver2007LookAndFeel());
SwingUtilities.updateComponentTreeUI(frame);
} catch (UnsupportedLookAndFeelException e) {
throw new RuntimeException(e);
}
}
});
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
System.out.println(info.getName());
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (UnsupportedLookAndFeelException e) {
// handle exception
} catch (ClassNotFoundException e) {
// handle exception
} catch (InstantiationException e) {
// handle exception
} catch (IllegalAccessException e) {
// handle exception
}
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}*/
UIResource res = new BorderUIResource.LineBorderUIResource(Color.red);
UIManager.put("PopupMenu.border", res);
JPopupMenu popupMenu = new JPopupMenu("Title");
//force to the Heavyweight Component or able for AWT Components
popupMenu.setLightWeightPopupEnabled(false);
PopupMenuListener popupMenuListener = new MyPopupMenuListener();
popupMenu.addPopupMenuListener(popupMenuListener);
JLabel lbl1 = new JLabel("My Title");
lbl1.setHorizontalAlignment(SwingConstants.CENTER);
popupMenu.add(lbl1);
JTextField text = new JTextField("My Title");
text.setHorizontalAlignment(SwingConstants.CENTER);
popupMenu.add(text);
String[] list = {"1", "2", "3", "4",};
JComboBox comb = new JComboBox(list);
popupMenu.add(comb);
JMenuItem pasteMenuItem = new JMenuItem("Paste");
pasteMenuItem.setEnabled(false);
popupMenu.add(pasteMenuItem);
popupMenu.addSeparator();
JMenuItem findMenuItem = new JMenuItem("Find");
popupMenu.add(findMenuItem);
JButton btn = new JButton();
JLabel lbl = new JLabel("My Title");
lbl.setHorizontalAlignment(SwingConstants.CENTER);
btn.setComponentPopupMenu(popupMenu);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(btn, BorderLayout.CENTER);
frame.add(lbl, BorderLayout.NORTH);
frame.setSize(350, 150);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
}
5 and terrible alignment for JLabel if there is added JComboBox :-) brrrrr !!!!

来源:https://stackoverflow.com/questions/8546073/how-to-force-jpopupmenu-to-show-title-even-if-look-and-feel-ui-dictates-otherwis