Layout JPopupMenu:如何在同一菜单中为菜单项提供不同的大小

时间:2015-03-20 12:36:00

标签: java swing jpopupmenu

我在菜单中需要两列菜单项。这可以使用GridBagLayout实现弹出菜单。我的问题是:两列的宽度相同,即菜单中最大菜单项的宽度(但不是列,因为它必须是GridBagLayout)。当我通过按钮替换菜单中的菜单项时 - 布局正常。那么我该如何建议菜单中的项目宽度不同?

以下是屏幕:

当我使用菜单项时 - 两列的宽度相同(错误) Wrong layout for menu items

当我使用按钮时 - 列具有不同的宽度(正确) Correct layout for buttons

以下是代码示例:

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);
    }
}

2 个答案:

答案 0 :(得分:3)

显然,JMenuItem布局基于同一父组件中包含的所有JMenutItem的最大宽度。在查看Sun / Oracle的代码之后,似乎很难干扰这一点,并且每个JMenuItem的首选大小将是等效的。

然而,我找到了一种方法来克服这个问题,通过覆盖getPreferredSize()的{​​{1}},不是很漂亮,但似乎有效:

JMenutItem

当然,如果您使用JMenuItem的其他属性来修改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); } } 的UI,您还需要将其传递给“内部”JMenuItem。它也可能难以维护,并且不适用于所有L& F。

您也可以通过在不同的通话中重复使用相同的“内部”JMenuItem来改善这一点。

答案 1 :(得分:2)

我只能说,在计算菜单项的大小时,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或JPopupMenu)仅包含JMenuItems,则所有菜单项的大小都相同。如果容器包含菜单项和其他组件的混合,则菜单项将以其首选大小显示(当然,取决于布局管理器)。