0

When adding plain text items to a menu, whether JMenu or JPopupMenu, each menu item has a height presumably based on its font plus some blank edges, which looks nice.

Adding an Icon to an item causes the item's height to be reduced to the height of the icon. If the icon's height is smaller than the font's size, then the item height is clearly bottoming out at the font's minimum height.

The closest post I could find was Setting icon in JMenuItem makes menu text match icon color, but color isn't a problem here. I've used a similar SSCCE:

import java.awt.*;
import javax.swing.*;

public class SquishText extends JFrame
{
    public SquishText()
    {
        JMenu menu = new JMenu("a menu");

        menu.add(new JMenuItem("item with no icon"));
        menu.add(new JMenuItem("label text goes here", new Icon(){
            @Override
            public void paintIcon (Component c, Graphics g, int x, int y) {
                ((Graphics2D)g).fill3DRect (0, 0, 8, 8, true);
            }
            @Override
            public int getIconWidth() {
                return 8;
            }
            @Override
            public int getIconHeight() {
                return 8;
            }
        }));
        menu.add(new JMenuItem("another item with no icon"));

        JMenuBar menubar = new JMenuBar();
        menubar.add(menu);
        this.setJMenuBar(menubar);
    }


    public static void main (String[] args) throws Exception
    {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        SquishText wtf = new SquishText();
        wtf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        wtf.setVisible(true);
    }
}

with results posted here: https://i.stack.imgur.com/3sJej.jpg

enter image description here enter image description here

Mousing over the menu items shows the height of the middle entry to be visibly smaller and ugly.

For adding Icons in our actual code, they've tried both our preferred method of setting data on the Action,

action.putValue (Action.SMALL_ICON, the_icon_instance);

and as a desperate fallback, setting it on the created JMenuItem directly,

menu.add(action).setIcon(the_icon_instance);

Same behavior in both cases, which matches the SSCCE. How the icon gets added doesn't seem to matter, just the fact that an icon is present.

It might be a problem with the L&F (Java 8 on Windows 7), but trying to poke around inside the WindowsLookAndFeel code was immediately bewildering.

So they've asked me for help, but this is the first I've encountered anything like this. (My projects rarely use icons in menus.) I feel like the whole thing could be solved with a setMinimumSize' / 'setPreferredSize in just the right spot, but I feel that shouldn't really be needed... and also we wouldn't know what the normal line height is until after rendering anyhow.

What noob mistake are we making here? (Pesky icons, back in my day it was all green text on a vt100, get off my lawn, etc.)

Community
  • 1
  • 1
Ti Strga
  • 1,353
  • 18
  • 40
  • 1
    This problem even occurs when the Icon is a regular ImageIcon. Sure looks like a bug in Swing. – VGR Jan 20 '17 at 19:03
  • @Frakcool thanks! I didn't realize we could do inlines here, I appreciate the edit. – Ti Strga Jan 20 '17 at 19:06
  • 1
    A workaround is to return a larger number from `getIconWidth()` and `getIconHeight()`, like 20. It seems to have something to do with the logic in SwingUtilities.layoutCompoundLabel, but I am still trying to understand why it isn’t a problem in other look-and-feels. – VGR Jan 20 '17 at 21:06
  • @VGR Interesting. Our "actual" Icon instances are all ImageIcons, but we could probably kludge something so that the getIcon* getters return deliberately large values. (The trick is making sure that actual drawing doesn't use those calls.) – Ti Strga Jan 20 '17 at 21:10
  • You also can pad your icon images with transparent pixels, either using an image editor, or at runtime in the code, by drawing each image onto a new 20×20 BufferedImage. – VGR Jan 20 '17 at 22:21

0 Answers0