Java Swing:当GridBagLayout列设置为增长时,如何使JLists正确调整大小,忽略JList的项目宽度?

时间:2018-04-23 10:12:46

标签: java swing layout-manager gridbaglayout

我得到了以下GridBagLayout: enter image description here

JLists的第一列和最后一列设置为grow: 1。无论包含的物品有多宽,我都希望这些JL主要具有相同的宽度。我怎样才能做到这一点?

我已经尝试使用list.setFixedCellWidth(100),但是周围的JScrollPane不再有用了。

3 个答案:

答案 0 :(得分:4)

所以,你的问题是多层次的。问题是,JList提供了两个用于确定JList

布局的值

第一个是getPreferredSizeJScrollPane将使用此方法来确定何时需要显示滚动条。

第二个是getPreferredScrollableViewportSize。这会为JScrollPane提供一个提示,这会影响它的preferredSize,它会向布局管理器提供有关如何布局的提示。

一种可能的解决方案是提供有关getPreferredScrollableViewportSize的更多信息,以便JList生成相同的值。然后,通过一些聪明的布局约束,您可以将两个列表保持为相同的大小。

因此,我们首先从JList延伸并提供查看preferredScrollableViewportSize的方法。

public class FixedSizeList<E> extends JList<E> {

    private Dimension preferredScrollableViewportSize;

    public FixedSizeList(ListModel<E> dataModel, Dimension preferredScrollableViewportSize) {
        super(dataModel);
        this.preferredScrollableViewportSize = preferredScrollableViewportSize;
    }

    @Override
    public Dimension getPreferredScrollableViewportSize() {
        if (preferredScrollableViewportSize != null) {
            return preferredScrollableViewportSize;
        }
        return super.getPreferredScrollableViewportSize();
    }

}

现在,就个人而言,我可能会尝试使用FontMetricsJList Font来确定应该如何最好地使用这些值,因此您可以提供columnrow值(或使用visibleRowCount属性)。这意味着值是“字符”而不是像素,但那只是我。

接下来,我们需要约束布局,这样两个列表都不会占用50%的可用空间。

setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 0.5;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;

JList shortList = new FixedSizeList(new ShortModel(), new Dimension(150, 300));
JList longList = new FixedSizeList(new LongModel(), new Dimension(150, 300));

add(new JScrollPane(shortList), gbc);
gbc.gridx += 2;
add(new JScrollPane(longList), gbc);

gbc.weightx = 0;
gbc.gridx = 1;

JPanel buttons = new JPanel(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.fill = gbc.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
for (int index = 0; index < 5; index++) {
    buttons.add(new JButton(Integer.toString(index)), gbc);
}
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
add(buttons, gbc);

这是一种有趣的说法,“两个列表都将填满剩余的可用空间”。由于我们对scrollableViewportSize进行了额外的约束,因此这将为两个列表提供相等的间距

Equal column widths

这是一些“重”的东西(恕我直言),但每当你向它添加一个新元素时,它都会循环遍历两个模型的所有元素

可运行的示例......

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.Random;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 1.0;
            gbc.weighty = 1.0;
            gbc.fill = GridBagConstraints.BOTH;

            JList shortList = new FixedSizeList(new ShortModel(), new Dimension(150, 300));
            JList longList = new FixedSizeList(new LongModel(), new Dimension(150, 300));

            add(new JScrollPane(shortList), gbc);
            gbc.gridx += 2;
            add(new JScrollPane(longList), gbc);

            gbc.weightx = 0;
            gbc.gridx = 1;

            JPanel buttons = new JPanel(new GridBagLayout());
            gbc = new GridBagConstraints();
            gbc.fill = gbc.HORIZONTAL;
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            for (int index = 0; index < 5; index++) {
                buttons.add(new JButton(Integer.toString(index)), gbc);
            }
            gbc = new GridBagConstraints();
            gbc.gridx = 1;
            gbc.gridy = 0;
            gbc.weighty = 1.0;
            gbc.fill = GridBagConstraints.BOTH;
            add(buttons, gbc);
        }

    }

    public class FixedSizeList<E> extends JList<E> {

        private Dimension preferredScrollableViewportSize;

        public FixedSizeList(ListModel<E> dataModel, Dimension preferredScrollableViewportSize) {
            super(dataModel);
            this.preferredScrollableViewportSize = preferredScrollableViewportSize;
        }

        @Override
        public Dimension getPreferredScrollableViewportSize() {
            if (preferredScrollableViewportSize != null) {
                return preferredScrollableViewportSize;
            }
            return super.getPreferredScrollableViewportSize();
        }

    }

    public class SizableModel extends DefaultListModel<String> {

        public String makeText(int length) {
            StringBuilder sb = new StringBuilder(length);
            for (int index = 0; index < length; index++) {
                String text = Integer.toString(index);
                sb.append(text.substring(text.length() - 1));
            }
            return sb.toString();
        }

    }

    public class ShortModel extends SizableModel {

        public ShortModel() {
            Random rnd = new Random();
            for (int index = 0; index < 5; index++) {
                addElement(makeText(Math.max(1, rnd.nextInt(5))));
            }
        }

    }

    public class LongModel extends SizableModel {

        public LongModel() {
            Random rnd = new Random();
            for (int index = 0; index < 10; index++) {
                addElement(makeText(Math.max(5, rnd.nextInt(15))));
            }
        }

    }
}

答案 1 :(得分:2)

您需要在JLists上设置原型单元格值

jList.setPrototypeCellValue("asdf");

在两个JLists上设置相同的文本。然后JList会假装&#34;所有项目都与提供的文本一样宽。此宽度将用于确定是否需要滚动条,因此您应找到要添加到JList的最长项目并将原型设置为。

使用setFixedCellWidth(int)设置固定单元格宽度也可以,但您必须自己计算最宽文本的宽度。

答案 2 :(得分:1)

GridBagLayout无法做到这一点。但是,SpringLayout是。

SpringLayout使用起来很麻烦,所以它通常不是一个好的选择,但有一些事情可以做,其他布局不能。在这种情况下,它使一个组件的大小约束的能力取决于另一个组件的大小限制是适用的:

JPanel buttonsPanel = new JPanel(new GridLayout(0, 1, 6, 6));
buttonsPanel.add(new JButton("\u2190"));
buttonsPanel.add(new JButton("\u21c7"));
buttonsPanel.add(new JButton("\u21c9"));
buttonsPanel.add(new JButton("\u2192"));

JPanel centerPanel = new JPanel(new GridBagLayout());
centerPanel.add(buttonsPanel, new GridBagConstraints());
centerPanel.setBorder(BorderFactory.createEmptyBorder(0, 12, 0, 12));

centerPanel.setMaximumSize(new Dimension(
    centerPanel.getPreferredSize().width,
    centerPanel.getMaximumSize().height));

JList<String> leftList = new JList<>(new String[] {
    "Erwartete Gäste pro Segmentcode",
    "Restaurant Auslastungsvorschau",
    "Restaurant Tagesauslastung",
});

JList<String> rightList = new JList<>(new String[] {
    "Info",
    "Ressourcenauslastung",
    "Provisionsanzeige",
    "Umsatzstatistik",
    "Top Anzahl/Umsatz",
    "Mitgliedsübersicht",
    "Gastherkunft",
    "Capture rate",
});

JScrollPane leftPane = new JScrollPane(leftList);
JScrollPane rightPane = new JScrollPane(rightList);

SpringLayout.Constraints leftConstraints =
    new SpringLayout.Constraints(leftPane);

SpringLayout.Constraints rightConstraints =
    new SpringLayout.Constraints(rightPane);

SpringLayout.Constraints centerConstraints =
    new SpringLayout.Constraints(centerPanel);

Spring width = Spring.max(
    leftConstraints.getWidth(),
    rightConstraints.getWidth());

Spring height = Spring.max(
    leftConstraints.getHeight(),
    rightConstraints.getHeight());

leftConstraints.setWidth(width);
leftConstraints.setHeight(height);
rightConstraints.setWidth(width);
rightConstraints.setHeight(height);
centerConstraints.setHeight(height);

centerConstraints.setConstraint(SpringLayout.WEST,
    leftConstraints.getConstraint(SpringLayout.EAST));

rightConstraints.setConstraint(SpringLayout.WEST,
    centerConstraints.getConstraint(SpringLayout.EAST));

SpringLayout layout = new SpringLayout();
JPanel listsPanel = new JPanel(layout);

listsPanel.add(leftPane, leftConstraints);
listsPanel.add(centerPanel, centerConstraints);
listsPanel.add(rightPane, rightConstraints);

// Set width of container
layout.putConstraint(
    SpringLayout.EAST, listsPanel, 0,
    SpringLayout.EAST, rightPane);

// Set height of container
layout.putConstraint(
    SpringLayout.SOUTH, listsPanel, 0,
    SpringLayout.SOUTH, rightPane);