2

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

stefita
  • 1,785
  • 2
  • 20
  • 35

4 Answers4

4

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
  • 5,617
  • 2
  • 25
  • 30
1

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
  • 1,954
  • 2
  • 14
  • 18
0

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
  • 1,785
  • 2
  • 20
  • 35
  • 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 Aug 31 '09 at 08:08
  • 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 Aug 31 '09 at 08:09
0

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
  • 321,443
  • 19
  • 166
  • 288
  • 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 Aug 28 '09 at 15:30