GridBagLayout: элементы сжимаются на очень определенной высоте панели - PullRequest
0 голосов
/ 10 июня 2019

Я использую GridBagLayout для создания панели, состоящей из 4 подпанелей. 4 субпанели окрашены в пурпурный, синий, красный и голубой цвета, а основная панель - в зеленый. Цель состоит в том, чтобы расположить эти 4 субпанели определенным образом и теоретически, зеленый не должен показывать. К счастью, у меня есть рабочий пример того, чего я хочу достичь:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main {

    public static void main(String[] args) {

        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int width = d.width;
        int height = 1046;


        JFrame frame = new JFrame("4.5 test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel masterPanel = new JPanel(new GridBagLayout());
        masterPanel.setBackground(Color.GREEN);

        GridBagConstraints c = new GridBagConstraints();
        c.weightx = 1.0;
        c.weighty = 1.0;

    // 1
        JPanel leftUpper = new JPanel();
        leftUpper.setBackground(Color.MAGENTA);
        leftUpper.setPreferredSize(new Dimension(width/3, height/7));
        c.gridx = 0;
        c.gridy = 0;
        c.anchor = GridBagConstraints.NORTH;
        masterPanel.add(leftUpper, c);


    // 2
        JPanel leftLower = new JPanel();
        leftLower.setBackground(Color.BLUE);
        leftLower.setPreferredSize(new Dimension(width/3, height - height/7));
        c.gridheight = 2;
        c.anchor = GridBagConstraints.SOUTH;
        masterPanel.add(leftLower, c);

    // 3
        JPanel rightUpper = new JPanel();
        rightUpper.setBackground(Color.RED);
        rightUpper.setPreferredSize(new Dimension(width - width/3, height - height/5));
        c.gridx = 1;
        c.gridheight = 1;
        masterPanel.add(rightUpper, c);


    // 4
        JPanel rightLower = new JPanel();
        rightLower.setBackground(Color.CYAN);
        rightLower.setPreferredSize(new Dimension(width - width/3, height/5));
        c.gridy = 1;
        masterPanel.add(rightLower, c);



        frame.add(masterPanel);
        frame.pack();
        frame.setVisible(true);
    }

}

При запуске это дает это правильный результат. Фактически, каждая высота меньше 1046 работает как задумано.

Однако момент меняет строку 16 на эту:

int height = 1047;

Все идет в ад, и вместо этого мы получаем . Это верно и для каждой высоты выше 1047. Панели находятся в правильных положениях, но далеко от правильных размеров. Обратите внимание, что в отличие от высоты, изменение ширины не имеет (непреднамеренного) эффекта.

Я бы не удивился такому поведению, если бы оно не было вызвано таким небольшим (произвольным?) Ограничением в размере. Для контекста я использую среду Java RunTime 1.8. У меня разрешение экрана компьютера 1920х1080. Почему это происходит, как можно это исправить, и если это жестокая практика, какую подробную альтернативу вы можете предоставить?

Ответы [ 2 ]

0 голосов
/ 12 июня 2019

Когда GridBagLayout не может вместить все предпочтительные размеры дочерних компонентов, он «сдается» и устанавливает для каждого отдельного дочернего компонента минимальный размер. Таким образом, одним из решений является установка минимального размера каждого компонента равным предпочтительному размеру.

Однако вместо того, чтобы математически учитывать каждый пиксель на экране, у вас есть более надежные варианты.

Одним из решений является установка размера только одной панели в любом конкретном измерении, чтобы другая всегда занимала оставшееся пространство. Таким образом, вы никогда не сможете «переполнить» доступное пространство. BorderLayout хорошо подходит для этого, поскольку его центральный компонент растянут, чтобы занять все доступное пространство, которое не используются боковыми компонентами.

Итак, для ваших пурпурных и синих панелей вы должны установить высоту только пурпурной панели:

JPanel leftPanel = new JPanel(new BorderLayout());

// 1
    JPanel leftUpper = new JPanel();
    leftUpper.setBackground(Color.MAGENTA);
    leftUpper.setPreferredSize(new Dimension(1, height/7));
    leftPanel.add(leftUpper, BorderLayout.NORTH);

// 2
    JPanel leftLower = new JPanel();
    leftLower.setBackground(Color.BLUE);
    leftPanel.add(leftLower, BorderLayout.CENTER);

И аналогично для красных и голубых:

JPanel rightPanel = new JPanel(new BorderLayout());

// 3
    JPanel rightUpper = new JPanel();
    rightUpper.setBackground(Color.RED);
    rightPanel.add(rightUpper, BorderLayout.CENTER);


// 4
    JPanel rightLower = new JPanel();
    rightLower.setBackground(Color.CYAN);
    rightLower.setPreferredSize(new Dimension(1, height/5));
    rightPanel.add(rightLower, BorderLayout.SOUTH);

И затем вы делаете что-то похожее на эти две панели, чтобы собрать их вместе:

    JPanel masterPanel = new JPanel(new BorderLayout());
    masterPanel.setBackground(Color.GREEN);

    leftPanel.setPreferredSize(new Dimension(width / 3,
        leftPanel.getPreferredSize().height));

    masterPanel.add(leftPanel, BorderLayout.WEST);
    masterPanel.add(rightPanel, BorderLayout.CENTER);

А поскольку сообщение о границах, заданных окнам системным диспетчером окон, ненадежно, вы избегаете какой-либо явной математики и просто максимизируете окно:

    frame.add(masterPanel);
    frame.pack();
    frame.setExtendedState(Frame.MAXIMIZED_BOTH);
    frame.setVisible(true);

Если вам абсолютно необходимо поддерживать соотношение между панелями (например, magenta_height: blue_height :: 1: 6), вы можете сделать это с помощью SpringLayout , но SpringLayout более сложный и обычно не не стоит хлопот Позволяет указать диапазоны размеров, которые могут быть кратны другим диапазонам размеров:

    SpringLayout layout = new SpringLayout();

    JPanel masterPanel = new JPanel(layout);
    masterPanel.setBackground(Color.GREEN);

// 1
    JPanel leftUpper = new JPanel();
    leftUpper.setBackground(Color.MAGENTA);
    masterPanel.add(leftUpper);

// 2
    JPanel leftLower = new JPanel();
    leftLower.setBackground(Color.BLUE);
    masterPanel.add(leftLower);

// 3
    JPanel rightUpper = new JPanel();
    rightUpper.setBackground(Color.RED);
    masterPanel.add(rightUpper);

// 4
    JPanel rightLower = new JPanel();
    rightLower.setBackground(Color.CYAN);
    masterPanel.add(rightLower);

    Spring leftUpperHeight = Spring.height(leftUpper);
    Spring leftLowerHeight = Spring.scale(leftUpperHeight, 6);

    Spring rightLowerHeight = Spring.scale(leftUpperHeight, 7 / 5f);

    Spring leftWidth = Spring.width(leftUpper);
    Spring rightWidth = Spring.scale(leftWidth, 3);

    layout.getConstraints(leftLower).setHeight(leftLowerHeight);
    layout.getConstraints(rightLower).setHeight(rightLowerHeight);

    layout.getConstraints(rightUpper).setWidth(rightWidth);
    layout.getConstraints(rightLower).setWidth(rightWidth);

    // Place leftLower beneath leftUpper.
    layout.putConstraint(
        SpringLayout.NORTH, leftLower, 0,
        SpringLayout.SOUTH, leftUpper);

    // Make leftLower's width match leftUpper's width.
    layout.putConstraint(
        SpringLayout.WEST, leftLower, 0,
        SpringLayout.WEST, leftUpper);
    layout.putConstraint(
        SpringLayout.EAST, leftLower, 0,
        SpringLayout.EAST, leftUpper);

    // Make container high enough to hold both leftLower and leftUpper.
    layout.putConstraint(
        SpringLayout.SOUTH, masterPanel, 0,
        SpringLayout.SOUTH, leftLower);

    // Place rightUpper and rightLower to the right of leftUpper.
    layout.putConstraint(
        SpringLayout.WEST, rightLower, 0,
        SpringLayout.EAST, leftUpper);
    layout.putConstraint(
        SpringLayout.WEST, rightUpper, 0,
        SpringLayout.WEST, rightLower);

    // Make container wide enough to accommodate rightUpper and rightLower.
    layout.putConstraint(
        SpringLayout.EAST, masterPanel, 0,
        SpringLayout.EAST, rightLower);

    // Align bottom of rightLower with bottom of leftLower.
    layout.putConstraint(
        SpringLayout.SOUTH, rightLower, 0,
        SpringLayout.SOUTH, leftLower);

    // Place rightUpper above rightLower.
    layout.putConstraint(
        SpringLayout.SOUTH, rightUpper, 0,
        SpringLayout.NORTH, rightLower);

    // Stretch rightUpper to reach to the top of the container.
    layout.putConstraint(
        SpringLayout.NORTH, rightUpper, 0,
        SpringLayout.NORTH, masterPanel);
0 голосов
/ 11 июня 2019

GridBagLayout ведет себя странно, когда недостаточно места для размера компонентов, по крайней мере, до их предпочтительного размера.Он не ухудшается изящно.

Кажется, вы пытаетесь создать абсолютный макет.GridBagLayout и другие общие LayoutManger s (другие менеджеры компоновки XY) не работают в этих ситуациях.

Придерживаясь GridBagLayout, обычно лучше использовать его внутри JScrollPane илипо крайней мере JPanel с минимальным размером, взятым из его предпочтительного размера.

...