Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 布局JPopupMenu:如何为同一菜单中的菜单项提供不同的大小_Java_Swing_Jpopupmenu - Fatal编程技术网

Java 布局JPopupMenu:如何为同一菜单中的菜单项提供不同的大小

Java 布局JPopupMenu:如何为同一菜单中的菜单项提供不同的大小,java,swing,jpopupmenu,Java,Swing,Jpopupmenu,我需要菜单中的两列菜单项。这可以通过使用GridBagLayout作为弹出菜单来实现。我的问题是:两列的宽度都相同,这是菜单中最大菜单项的宽度(但不是在列中,因为GridBagLayout必须如此)。当我用按钮替换菜单中的菜单项时,布局正确。那么,我如何建议菜单中的项目应该有不同的宽度呢 以下是屏幕: 使用菜单项时-两列的宽度相同(错误) 使用按钮时,列的宽度不同(正确) 下面是代码示例: import java.awt.GridBagConstraints; import java.awt

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

以下是屏幕:

使用菜单项时-两列的宽度相同(错误)

使用按钮时,列的宽度不同(正确)

下面是代码示例:

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使用一点“魔力”为所有菜单项提供相同的大小。我已经测试了混合盒,但所有菜单项的宽度都相同。