Java JPopupMenu菜单项和组件

Java JPopupMenu菜单项和组件,java,swing,jpopupmenu,Java,Swing,Jpopupmenu,我有一个弹出菜单,其中包含一个带有图标(I)和JList的JMenuItem。见下图 ------------------------ | I | Clear | |----------------------| | | List |^| | | Item A | | | | Item B | | | | Item C | | | | |v| -------

我有一个弹出菜单,其中包含一个带有图标(I)和JList的JMenuItem。见下图

------------------------
| I | Clear            |
|----------------------|
|   | List           |^|
|   | Item A         | |
|   | Item B         | |
|   | Item C         | |
|   |                |v|
------------------------
当我最初创建弹出窗口时,列表与左侧对齐,没有考虑图标偏移

我能够找到一种使用
sun.swing.swingutilities 2.BASICMENUITEMUI\u MAX\u TEXT\u OFFSET
客户端属性移动列表的方法

// 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);
但是,我无法在生产代码中使用该常量(因为它在sun包中)


如何在不依赖Java内部构件的情况下检索最大文本/图标偏移量?

一个常见的解决方案是为每个菜单项添加一个与菜单图标大小相同的空图标

您可以使用下面代码中的概念,其中使用:

SwingUtilities.layoutCompoundLabel(...);
基本上,它获取标签的布局信息,以确定文本和图标相对于整个标签的实际绘制位置。如果你知道这些信息,你就应该有你的偏移量

此示例仅在标签中的图标上绘制网格线:

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();
            }
        });
    }
}
import java.awt.*;
导入javax.swing.*;
导入javax.swing.border.*;
公共类LabelLayout扩展JLabel
{
@凌驾
受保护组件(图形g)
{
超级组件(g);
图形网格=g.create();
grid.setColor(Color.ORANGE);
矩形视图=新矩形();
viewR.width=getSize().width;
viewR.height=getSize().height;
矩形iconR=新矩形();
矩形文本=新矩形();
String clippedText=SwingUtilities.layoutCompoundLabel
(
这
grid.getFontMetrics(),
getText(),
getIcon(),
getVerticalAlignment(),
getHorizontalAlignment(),
getVerticalTextPosition(),
getHorizontalTextPosition(),
viewR,
iconR,
发短信,
getIconTextGap()
);
int gridSize=10;
int start=iconR.x;
int end=iconR.x+iconR.width;
系统输出打印项次(iconR);
for(int i=开始;i<结束;i+=网格大小)
{
网格绘制线(i,图标编号y,i,图标编号y+图标编号高度);
}
grid.dispose();
//g.setColor(get前台());
//g.drawString(display,textR.x,textR.y+fm.getHeight());
//System.out.println(iconR+“:”+textR);
}
私有静态void createAndShowGUI()
{
LabelLayout标签=新LabelLayout();
label.setboorder(新线条边框(颜色为红色));
label.setText(“某些文本”);
label.setIcon(新的图像图标(“dukewaveed.gif”);
标签。设置垂直对齐(JLabel.CENTER);
标签。设置水平对齐(JLabel.CENTER);
//label.setVerticalTextPosition(JLabel.BOTTOM);
label.setVerticalTextPosition(JLabel.TOP);
label.setHorizontalTextPosition(JLabel.CENTER);
JFrame=新JFrame(“SSCCE”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
框架。添加(标签);
frame.setLocationByPlatform(真);
frame.pack();
框架。设置尺寸(300200);
frame.setVisible(true);
}
公共静态void main(字符串[]args)
{
invokeLater(新的Runnable()
{
公开募捐
{
createAndShowGUI();
}
});
}
}

我认为JMenu会使用相同的布局。

您在弹出窗口上使用的布局管理器是什么?考虑提供一个说明你的问题的方法。这不是一个代码转储,而是您正在做的一个示例,它突出了您所遇到的问题。这将减少混乱并获得更好的响应
我能够找到一种使用
移动列表的方法-如何使用信息?发布显示您正在执行的操作的代码。@mad程序员我正在使用的是
BoxLayout
jpopmpmenu
(我相信
JMenu
)使用
BoxLayout
。如果菜单中的所有组件都是菜单项,那么这将很好地工作。我看不出其他组件是如何工作的。此外,这似乎非常特定于单个L&F的工作方式。@screenmutt,我不知道你为什么提到BoxLayout。BoxLayout与单个菜单项的显示方式无关。我也给出了两种解决方案,我不确定你的评论适用于哪种解决方案。解决方案1是最简单的。我建议第二种解决方案作为可能(或可能不)有效的替代方案。您只需要测试它,不要假设它会或不会工作。由于您没有发布可运行代码,我无法验证解决方案。祝你好运