Java 布局JPopupMenu:如何为同一菜单中的菜单项提供不同的大小
我需要菜单中的两列菜单项。这可以通过使用GridBagLayout作为弹出菜单来实现。我的问题是:两列的宽度都相同,这是菜单中最大菜单项的宽度(但不是在列中,因为GridBagLayout必须如此)。当我用按钮替换菜单中的菜单项时,布局正确。那么,我如何建议菜单中的项目应该有不同的宽度呢 以下是屏幕: 使用菜单项时-两列的宽度相同(错误) 使用按钮时,列的宽度不同(正确) 下面是代码示例:Java 布局JPopupMenu:如何为同一菜单中的菜单项提供不同的大小,java,swing,jpopupmenu,Java,Swing,Jpopupmenu,我需要菜单中的两列菜单项。这可以通过使用GridBagLayout作为弹出菜单来实现。我的问题是:两列的宽度都相同,这是菜单中最大菜单项的宽度(但不是在列中,因为GridBagLayout必须如此)。当我用按钮替换菜单中的菜单项时,布局正确。那么,我如何建议菜单中的项目应该有不同的宽度呢 以下是屏幕: 使用菜单项时-两列的宽度相同(错误) 使用按钮时,列的宽度不同(正确) 下面是代码示例: import java.awt.GridBagConstraints; import java.awt
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;
public class MenuTest {
public static void main(String[] args) {
JFrame frm = new JFrame("Menu test");
JMenuBar menuBar = new JMenuBar();
JMenu m1 = new JMenu("Menu items");
m1.getPopupMenu().setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
m1.getPopupMenu().add(new JMenuItem("Very very very very long text"), gbc);
gbc.gridx = 1;
m1.getPopupMenu().add(new JMenuItem("Short text"), gbc);
menuBar.add(m1);
JMenu m2 = new JMenu("Buttons");
m2.getPopupMenu().setLayout(new GridBagLayout());
gbc.gridx = 0;
m2.getPopupMenu().add(new JButton("Very very very very long text"), gbc);
gbc.gridx = 1;
m2.getPopupMenu().add(new JButton("Short text"), gbc);
menuBar.add(m2);
frm.setJMenuBar(menuBar);
frm.add(new JScrollPane(new JTextArea("Sample text", 10, 40)));
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
}
显然,
JMenuItem
布局基于同一父组件中包含的所有JMenuItem
的最大宽度。在查看Sun/Oracle的代码后,似乎很难对此进行干预,每个JMenuItem
的首选大小将是相等的
然而,我找到了一种克服这一问题的方法,即覆盖JMenutItem
的getPreferredSize()
,虽然不美观,但似乎有效:
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
public class MenuTest {
public static void main(String[] args) {
JFrame frm = new JFrame("Menu test");
JMenuBar menuBar = new JMenuBar();
JMenu m1 = new JMenu("Menu items");
m1.getPopupMenu().setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
JMenuItem comp1 = new JMenuItem("Very very very very long text") {
@Override
public Dimension getPreferredSize() {
return new JMenuItem(getText(), getIcon()).getPreferredSize();
}
};
m1.getPopupMenu().add(comp1, gbc);
gbc.gridx = 1;
JMenuItem comp2 = new JMenuItem("Short text") {
@Override
public Dimension getPreferredSize() {
return new JMenuItem(getText(), getIcon()).getPreferredSize();
}
};
m1.getPopupMenu().add(comp2, gbc);
menuBar.add(m1);
JMenu m2 = new JMenu("Buttons");
m2.getPopupMenu().setLayout(new GridBagLayout());
gbc.gridx = 0;
m2.getPopupMenu().add(new JButton("Very very very very long text"), gbc);
gbc.gridx = 1;
m2.getPopupMenu().add(new JButton("Short text"), gbc);
menuBar.add(m2);
frm.setJMenuBar(menuBar);
frm.add(new JScrollPane(new JTextArea("Sample text", 10, 40)));
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
comp1.setVerticalTextPosition(SwingConstants.TOP);
comp2.setVerticalTextPosition(SwingConstants.TOP);
}
}
当然,如果您使用JMenuItem的其他属性来修改JMenuItem
的UI,那么还需要将其传递给“内部”JMenuItem
。它也可能很难维护,并且不会在所有L&F中都起作用
您还可以通过在不同的调用中重新使用相同的“内部”JMenuItem来改进这一点。我能说的是,当计算菜单项的大小时,JMenuItem似乎有一些奇怪的逻辑。查看
BasicMenuItemUI
类,似乎可以使用MenuItemLayoutHelper
类来帮助计算菜单项的首选大小。此类位于sun.swing.*
包中,因此我无法查看代码
无论如何,我做了更多的测试,试图确定组件的首选尺寸,因为它们是使用以下代码添加到面板中的:
import java.awt.*;
import javax.swing.*;
public class Main
{
public static void main(String[] args) throws Exception
{
JMenuItem mi1 = new JMenuItem("Very very very long text");
JMenuItem mi2 = new JMenuItem("Shorter text");
JButton b1 = new JButton("Very very very long text");
JButton b2 = new JButton("Shorter text");
System.out.println("Menu Items:");
createPanel(mi1, mi2);
System.out.println("Buttons:");
createPanel(b1, b2);
System.out.println("mixture:");
createPanel(mi2, b1);
}
public static void createPanel(Component c1, Component c2)
{
System.out.println(c1.getPreferredSize() + " : " + c2.getPreferredSize());
JPanel panel = new JPanel( new GridBagLayout() );
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
panel.add(c1, gbc);
System.out.println("p1: " + panel.getPreferredSize());
gbc.gridx = 1;
panel.add(c2, gbc);
System.out.println("p2: " + panel.getPreferredSize());
}
}
我得到以下输出:
Menu Items:
java.awt.Dimension[width=153,height=21] : java.awt.Dimension[width=89,height=21]
p1: java.awt.Dimension[width=153,height=21]
p2: java.awt.Dimension[width=306,height=21]
Buttons:
java.awt.Dimension[width=166,height=26] : java.awt.Dimension[width=102,height=26]
p1: java.awt.Dimension[width=166,height=26]
p2: java.awt.Dimension[width=268,height=26]
mixture:
java.awt.Dimension[width=153,height=21] : java.awt.Dimension[width=166,height=26]
p1: java.awt.Dimension[width=89,height=21]
p2: java.awt.Dimension[width=255,height=26]
在“菜单项”示例中,第二个菜单项的宽度为89
,但是,当添加到面板时,它神奇地获得了153
(与第一个菜单项的宽度相同)
“按钮”示例按预期工作。每个按钮(166和102)的首选宽度反映在268的面板宽度中
在“混合”示例中,菜单项宽度显示为153
在“菜单项”示例中使用时指定的宽度。但是,一旦添加菜单项,面板的宽度就会下降到预期的宽度89
这告诉我,菜单项的首选大小实际上是添加到容器中的最大菜单项的大小
因此,如果容器(JPanel或jpopmpmenu)只包含JMenuItems,那么所有菜单项的大小都相同。如果容器包含菜单项和其他组件的混合物,则菜单项将以其首选大小显示(当然取决于布局管理器)。,在变成之前有BoxLayout和popup required pack()visible@mKorbel
pack()
在此无效谢谢您的调查。这也是我的假设,MenuItemUI或PopupMenuUI使用一点“魔力”为所有菜单项提供相同的大小。我已经测试了混合盒,但所有菜单项的宽度都相同。