tags:

views:

360

answers:

4

I try to set a minimum width for my menu items, but it doesn't seem to work. Here is my function, which creates the items:

 private JMenuItem newItem(String text, String iconPath) {
  JMenuItem myMenuItem;
  if (iconPath == null || iconPath.isEmpty()) {
   myMenuItem = new JMenuItem(text);
  }
  else {
   ImageIcon icon = new ImageIcon(iconPath);
   myMenuItem = new JMenuItem(text, icon);
  }
  // this would work, but then setMaximumSize doesn't have any effect
  // myMenuItem.setPreferredSize(new Dimension(250,20)); 
  myMenuItem.setMinimumSize(new Dimension(250,20)); 
  myMenuItem.setMaximumSize(new Dimension(350,20));

  return myMenuItem;
 }

What am I doing wrong?

PS. I'm using jdk1.6 on Windows XP, Servicepack 3 with the System Look&Feel

+1  A: 

i replaced your

myMenuItem.setMinimumSize(new Dimension(250, 20));
myMenuItem.setMaximumSize(new Dimension(350, 20));

with

myMenuItem.setPreferredSize(new Dimension(250, 20));

and it makes it the width you were looking for. In my experience swing components respond better to preferred size than min and max size.

EDIT:

after taking another stab i think this works pretty well.. it boils down to much the same as you have and i think it'll work no matter what the font (where as you've hardcoded the font).

it does however not take into account the leading gutter of a menu item, but unless you're text is really significantly long it shouldn't make a difference..

 private JMenuItem newItem(String text, String iconPath) {
    JMenuItem myMenuItem;
    if (iconPath == null || iconPath.isEmpty()) {
        myMenuItem = new JMenuItem(text);
        myMenuItem.setPreferredSize(new Dimension(myMenuItem.getFontMetrics(myMenuItem.getFont()).stringWidth(text), 20));
    } else {
        ImageIcon icon = new ImageIcon(iconPath);
        myMenuItem = new JMenuItem(text, icon);
        myMenuItem.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
    }
    return myMenuItem;
}
Nico
well yes, but if a menu item is larger than 250px then it's not fully shown.
stefita
fair enough, but why not just set the preferredSize width to icon.getIconWidth(); ?
Nico
the icon is not the issue, but the text node. Is there a way to determine how many pixels a string would take (in the system font)?
stefita
yeah, but it ain't pretty myMenuItem.getGraphics().getFontMetrics().stringWidth(text); take into account that this wont include fractional increases in width due to antialiasing, but that should be negligible.
Nico
I tried that, but it gave me a big exception (dunno why...). Thanks anyway!
stefita
see edit above :)
Nico
A: 

Ok, so I found A solution, perhaps not the best one but it seems to work. I'm still a bit worried about the FontMetrics statement, though. So if anyone has a better solution, I would be glad to see it. Here is my code (Menu.MINWIDTH is set to 200 and Menu.MAXWIDTH to 300):

 private JMenuItem newItem(String text, String iconPath) {
  JMenuItem myMenuItem;
  ImageIcon icon= null;
  int iconPixels = 0;
  if (iconPath == null || iconPath.isEmpty()) {
   myMenuItem = new JMenuItem(text);
  }
  else {
   icon = new ImageIcon(iconPath);
   myMenuItem = new JMenuItem(text, icon);
   iconPixels = icon.getIconWidth();
  }

  FontMetrics fontM = myMenuItem.getFontMetrics(new Font("Default", Font.PLAIN, 12));
  int stringPixels = fontM.stringWidth(text);

  int newWidth = stringPixels + iconPixels;

  newWidth = newWidth < Menu.MINWIDTH ? Menu.MINWIDTH : newWidth;
  newWidth = newWidth > Menu.MAXWIDTH ? Menu.MAXWIDTH : newWidth;

  myMenuItem.setPreferredSize(new Dimension(newWidth, 20)); 
  System.out.println(text + " - " + newWidth);
  return myMenuItem;
 }
stefita
Instead of using font metrics, you could just construct a `JLabel` with the font, text, and icon, and get its preferred size. It should be the same as the default preferred size of the `JMenuItem`, or near enough.
David Moles
Actually -- I only just noticed that you're constructing the menu item here -- you don't even need the `JLabel`; you can just use the menu item's own original preferred size, as in Russ Hayward's answer.
David Moles
A: 

If I understand the question I'm not sure why you need to use the FontMetrics. Just invoke getPreferredSize() on the menu item. If the preferred size is less than your minimum then reset the preferred size to your minimum.

camickr
well the size should vary according to the length of the item's text. If the text is longer then the minimum, the menu item should change its width, but no more than the allowed maximum.
stefita
+2  A: 

Minimum and maximum sizes are ignored by most layout managers. Here is a useful little trick that forces those sizes to be respected in any layout manager:

private class MyMenuItem extends JMenuItem {
    @Override
    public Dimension getPreferredSize() {
        Dimension preferred = super.getPreferredSize();
        Dimension minimum = getMinimumSize();
        Dimension maximum = getMaximumSize();
        preferred.width = Math.min(Math.max(preferred.width, minimum.width), 
            maximum.width);
        preferred.height = Math.min(Math.max(preferred.height, minimum.height), 
            maximum.height);
        return preferred;
    }
}

This has the advantage of working even if the contents of the menu item changes. You will need to add constructors to suit your purposes.

Russ Hayward
That's a good workaround! Thank you!
stefita