Dan Grahn
Dan Grahn

Reputation: 9394

JPopupMenu Menu Items and Components

I have a popup menu which contains a JMenuItem with an icon (I) and a JList. See the diagram below.

------------------------
| I | Clear            |
|----------------------|
|   | List           |^|
|   | Item A         | |
|   | Item B         | |
|   | Item C         | |
|   |                |v|
------------------------

When I initially created the popup, the list was aligned to the left hand side and did not take into account the icon offset.

I was able to find a way to move the list using the sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET client property.

// Move the items out of the gutter (Run inside of the show(Component, int, int) method)
final Integer gutter = (Integer) getClientProperty(SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET);
panelList.removeAll();
panelList.add(Box.createHorizontalStrut(gutter));
panelList.add(scrollList);

However, I am unable to use that constant in production code (due to it being in the sun package).

How can I retrieve the max text/icon offset without relying upon Java's internals?

Upvotes: 0

Views: 859

Answers (1)

camickr
camickr

Reputation: 324088

One common solution for this is to add an empty Icon for each menu item that is the same size as the Icon for the menu.

You might be able to use the concepts from the code below which uses:

SwingUtilities.layoutCompoundLabel(...);

Basically it get the layout information of the label to determine where the text and icon are actually painted relative to the entire label. If you know that information you should then have your offset.

This example paints grid lines only over the Icon in the label:

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

public class LabelLayout extends JLabel
{
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics grid = g.create();
        grid.setColor( Color.ORANGE );

        Rectangle viewR = new Rectangle();
        viewR.width = getSize().width;
        viewR.height = getSize().height;
        Rectangle iconR = new Rectangle();
        Rectangle textR = new Rectangle();

        String clippedText = SwingUtilities.layoutCompoundLabel
        (
            this,
            grid.getFontMetrics(),
            getText(),
            getIcon(),
            getVerticalAlignment(),
            getHorizontalAlignment(),
            getVerticalTextPosition(),
            getHorizontalTextPosition(),
            viewR,
            iconR,
            textR,
            getIconTextGap()
        );

        int gridSize = 10;
        int start = iconR.x;
        int end = iconR.x + iconR.width;

        System.out.println( iconR );

        for (int i = start; i < end; i += gridSize)
        {
            grid.drawLine(i, iconR.y, i, iconR.y + iconR.height);
        }

        grid.dispose();

//      g.setColor( getForeground() );
//      g.drawString(display, textR.x, textR.y + fm.getHeight());
//      System.out.println(iconR + " : " + textR);
    }

    private static void createAndShowGUI()
    {
        LabelLayout label = new LabelLayout();
        label.setBorder( new LineBorder(Color.RED) );
        label.setText( "Some Text" );
        label.setIcon( new ImageIcon( "DukeWaveRed.gif" ) );
        label.setVerticalAlignment( JLabel.CENTER );
        label.setHorizontalAlignment( JLabel.CENTER );
//      label.setVerticalTextPosition( JLabel.BOTTOM );
        label.setVerticalTextPosition( JLabel.TOP );
        label.setHorizontalTextPosition( JLabel.CENTER );

        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( label );
        frame.setLocationByPlatform( true );
        frame.pack();
        frame.setSize(300, 200);
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }
}

I think a JMenu would use the same layout.

Upvotes: 2

Related Questions