使用 GridBagLayout 在 JScrollPane 中设置 JList 的宽度

Setting the width of a JList in a JScrollPane with GridBagLayout

我有示例 Java 下面的 Swing 代码生成以下屏幕截图(屏幕截图已被编辑以使其更小):

这是代码:

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;


public class Main extends JFrame {

    public Main() {
        JListTest theGui = new JListTest();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        add(theGui);
        pack();
        setVisible(true);
    }

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

    private class JListTest extends JPanel {
        private static final int PADDING = 3;
        private JLabel label;
        private JTextArea textarea;
        private String listOptions[] = 
            {"here is some veeeeeeeeeeeeeeeeeeeeeeeeeerrrrrrrrrrrrrrrrrrrrrrrrrrrrry long text",
             "here is some more loooooooooooooooooooooooooooooooooooooooooooooooooooooong text",
             "here is some veeeeeeeeeeeeeeeeeeeeeeeeeerrrrrrrrrrrrrrrrrrrrrrrrrrrrry long text",
             "here is some more loooooooooooooooooooooooooooooooooooooooooooooooooooooong text",
             "here is some veeeeeeeeeeeeeeeeeeeeeeeeeerrrrrrrrrrrrrrrrrrrrrrrrrrrrry long text",
             "here is some more loooooooooooooooooooooooooooooooooooooooooooooooooooooong text",
             "here is some veeeeeeeeeeeeeeeeeeeeeeeeeerrrrrrrrrrrrrrrrrrrrrrrrrrrrry long text",
             "here is some more loooooooooooooooooooooooooooooooooooooooooooooooooooooong text",
             "here is some veeeeeeeeeeeeeeeeeeeeeeeeeerrrrrrrrrrrrrrrrrrrrrrrrrrrrry long text",
             "here is some more loooooooooooooooooooooooooooooooooooooooooooooooooooooong text"};
        private JList<String> list;
        private JScrollPane scrollpane;
        private GridBagConstraints gbc;

        public JListTest() {
            super(new GridBagLayout());
            label = new JLabel("Here is a label:");
            textarea = new JTextArea(20, 50);
            list = new JList<String>(listOptions);
            scrollpane = new JScrollPane(list);

            gbc = new GridBagConstraints();
            gbc.gridheight = 1;
            gbc.insets = new Insets(PADDING, PADDING, PADDING, PADDING);
            gbc.anchor = GridBagConstraints.LINE_START;

            gbc.gridwidth = 4;
            gbc.gridx = 0;
            gbc.gridy = 0;
            add(label, gbc);

            // I want the scrollpane to take up 1/4 the width of the window.
            gbc.gridwidth = 1;
            gbc.gridx = 0;
            gbc.gridy = 1;
            add(scrollpane, gbc);

            // I want the textarea to take up 3/4 the width of the window.
            gbc.gridwidth = 3;
            gbc.gridx = 1;
            gbc.gridy = 1;
            add(textarea, gbc);
        }
    }
}

如您所见,我有一个 JList,其中包含左侧 JScrollPane 和右侧 JTextArea 中带有很长文本的项目。我希望 JScrollPane/JList 占据 window 宽度的 1/4,并在 JList 项目的文本太长时出现水平滚动条。我希望 JTextArea 占据 window 宽度的 3/4。

我尝试使用 GridBagLayout 执行此操作,但显然我没有正确执行此操作,因为外观已关闭。

感谢任何帮助。谢谢!

定义 JScrollPane 的首选尺寸,以保持最初宽度的 1/4。然后为 JScrollPane 添加 weightX =1,为 JTextArea 添加 =3。

pack() 之后,您的初始状态将反映首选尺寸。如果宽度增加,则根据权重分配额外的像素。

GridBagLayout 想要使用组件的首选大小,这是您认为可以做的事情和实际可以做的事情发生冲突的奇怪点之一。

本质上,您想要做的是用您自己的逻辑覆盖 GridBagLayout 做出的布局决策(您占用 25% 的宽度和 75% 的宽度)。问题是,GridBagLayout 不这么想,它更多的是这样想,你可以拥有 space 的 25%,这是在我计算了每个人的首选布局要求之后剩下的,并且你可以有75%。这并不总是按照您最初认为的方式出现。

第一步,是利用weightxweighty

// I want the scrollpane to take up 1/4 the width of the window.
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = 1;
gbc.gridx = 0;
gbc.gridy = 1;
gbc.weightx = 0.25;
gbc.weighty = 1;
add(scrollpane, gbc);

// I want the textarea to take up 3/4 the width of the window.
gbc.gridx = 1;
gbc.gridy = 1;
gbc.weightx = 0.75;
add(textarea, gbc);

这为 GridBagLayout 提供了调整大小的提示,提示它应该如何处理完成初始布局后 space 可能有的剩余部分。

但是,等等,这似乎没有任何改变!不,实际上它不会,除非您将 window 的大小调整得足够大,正如我所说的那样,组件将(尽可能最好地)布局到它们的首选大小。所以 JListJTextArea 正在与我们争论不休。

A JScrollPane 从视图组件中获取它的首选大小。 JList 实现 Scrollable 接口,该接口提供 getPreferredScrollableViewportSize 方法,JScrollPane 使用它作为首选大小(否则它使用组件的首选大小)

所以,我们现在可以大胆地修改首选视口宽度...

list = new JList<String>(listOptions) {
    @Override
    public Dimension getPreferredScrollableViewportSize() {
        Dimension size = super.getPreferredScrollableViewportSize();
        size.width = 100;
        return size;
    }
};

(ps,我测试了setFixedCellWidthsetPrototypeCellValue,但是这两个都阻止了水平滚动条的出现。

好的,这个效果好一点:P。有时最小尺寸会与首选尺寸竞争,所以要小心 :P

请记住,weightx/y 仅适用于剩余的 space,它不会影响初始布局 :P