Убедитесь, что SpringLayout не сжимается ниже определенного размера

Я пытаюсь реализовать довольно простой пользовательский интерфейс, используя SpringLayout (отчасти потому, что я, в отличие от большинства авторов руководств, которых я нахожу в сети, очень похож на интерфейс кодирования по сравнению с другими менеджерами компоновки, а отчасти потому, что я хочу научиться его использовать ). Пользовательский интерфейс в основном выглядит так:

Шаблон пользовательского интерфейса

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

Интерфейс при сжатии

Я бы хотел, чтобы окно не допускало дальнейшего сжатия, чтобы, если пользователь попытается сжать окно до размера, меньшего, чем достаточно для размещения компонентов, оно просто остановится. Как мне это сделать, используя менеджер компоновки SpringLayout?

Я знаю, что мог бы сделать это, обработав событие изменения размера и проверив, достигнут ли минимальный размер, а затем просто установив минимальный размер. Но это требует от меня: а) знать или знать, как рассчитать минимальный размер окна, даже до его рендеринга, б) написать кучу кода обработки событий, чтобы получить правильный рендеринг пользовательского интерфейса, и в) написать куча кода для вещей, о которых я ожидаю, что хороший менеджер по расположению позаботится;)


person Tomas Aschan    schedule 03.01.2012    source источник


Ответы (2)


  1. вы можете переопределить MinimumSize для TopLevelContainer

  2. вы поставили JTextArea на JScrollPane

  3. Самый простой способ — смешать LayoutManagers (называемый NestedLayout) путем разделения графического интерфейса на части (разделить JPanels на одинаковые или разные LayoutManager), а не реализовывать некоторые наиболее сложные LayoutManager (GridBagLayout или SpringLayout) для целых Container

  4. некоторые LayoutManagers довольно игнорируют setXxxSize

  5. SpringLayout не моя чашка Java

import java.awt.*;
import javax.swing.*;

public class MinSizeForContainer {

    private JFrame frame = new JFrame("some frame title");

    public MinSizeForContainer() {
        JTextArea textArea = new JTextArea(15, 30);
        JScrollPane scrollPane = new JScrollPane(textArea);

        CustomJPanel fatherPanel = new CustomJPanel();
        fatherPanel.setLayout(new SpringLayout());

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(fatherPanel, BorderLayout.CENTER);
        frame.setLocation(20, 20);
        frame.setMinimumSize(fatherPanel.getMinimumSize());
        frame.pack();
        frame.setVisible(true);
    }

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

            @Override
            public void run() {
                MinSizeForContainer Mpgp = new MinSizeForContainer();
            }
        });
    }
}

class CustomJPanel extends JPanel {

    private static final long serialVersionUID = 1L;

    @Override
    public Dimension getMinimumSize() {
        return new Dimension(400, 400);
    }
}
person mKorbel    schedule 03.01.2012
comment
Видите ли, проблема здесь в том, что минимальный размер жестко запрограммирован. Я хочу полностью избежать этого, чтобы позже я мог решить добавить еще один элемент пользовательского интерфейса (скажем, длинный, но узкий список справа) и не переписывать ничего из этого в своем коде. - person Tomas Aschan; 04.01.2012
comment
+1 TextLayout, показанный здесь, — это способ получить минимальные границы, но подтвержденный предпочтительный размер тоже должен быть хорошим. . - person trashgod; 04.01.2012
comment
жесткое кодирование размеров в getXXSize почти так же плохо, как использование setXXSize ;-) - person kleopatra; 05.01.2012
comment
забыл: +1 за определение размера, гарантирующего (насколько позволяет ОС) контракт window.setMinimumSize - до вчерашнего дня не знал об этом :-) - person kleopatra; 06.01.2012
comment
@kleopatra один добрый урок от (@Andrew Thompson) - person mKorbel; 06.01.2012

Есть несколько проблем для достижения «реального» (который не может быть уменьшен) минимального размера:

  • дочерние компоненты должны возвращать некоторый разумный (в зависимости от их содержимого) минимальный размер, многие основные компоненты не
  • layoutManager должен учитывать совокупный минимум всех дочерних элементов, независимо от того, насколько мало места доступно
  • контейнер верхнего уровня (здесь JFrame) не должен допускать сжатия сверх минимального

Первое верно для JLabel, второе - для SpringLayout (поэтому метка усечена), что оставляет третью как основную проблему, решение которой неочевидно, на самом деле я не знал, что это даже возможно перед запуском примера @mKorbel. Соответствующая строка действительно

frame.setMinimumSize(someSize);

С этой линией невозможно уменьшить кадр ниже. Без, это. Исходя из этого наблюдения, некоторые копания оказываются документом для его переопределения в Window.

Устанавливает минимальный размер этого окна на постоянное значение. [..] Если размер текущего окна меньше минимального размера, размер окна автоматически увеличивается, чтобы соответствовать минимальному размеру. Если после этого вызываются методы setSize или setBounds с шириной или высотой меньше [...], автоматически увеличивается, чтобы соответствовать минимальному размеру. Операция изменения размера может быть ограничена, если пользователь попытается изменить размер окна ниже минимального значения. Это поведение зависит от платформы.

Глядя на код, есть две (реализация, не полагайтесь на них :-) детали, связанные с минимальным размером

 Dimension minSize;
 boolean minSizeSet;

и публичный API для доступа

 public Dimension getMinimumSize()
 public boolean isMininumSizeSet()

первый довольно старый (jdk1.1), второй - довольно новый (jdk1.5) - это означает, что первый не может полагаться на последний, но внутренне должен проверять нулевой minSize. Переопределенные методы изменения размера (с их гарантией того, что они делают все возможное для соблюдения установленного вручную minSize) в Window являются последними (jdk6) и действуют полагаются на последний. Или, другими словами: переопределение isMinimumSizeSet ​​делает свое дело.

Некоторый фрагмент кода (осторожно: это хак, непроверенный, вполне может зависеть от ОС с нежелательными побочными эффектами!):

    // JFrame.setDefaultLookAndFeelDecorated(true);
    JFrame frame = new JFrame("some frame title") {

        /**
         * Overridden to tricks sizing to respect the min.
         */
        @Override
        public boolean isMinimumSizeSet() {
            return true; //super.isMinimumSizeSet();
        }

        /**
         * Overridden to adjust for insets if tricksing and not using 
         * LAF decorations.
         */
        @Override
        public Dimension getMinimumSize() {
            Dimension dim = super.getMinimumSize();
            // adjust for insets if we are faking the isMinSet
            if (!super.isMinimumSizeSet() && !isDefaultLookAndFeelDecorated()) {
               Insets insets = getInsets();
               dim.width += insets.left + insets.right;
               dim.height += insets.bottom + insets.top;
            }
            return dim;
        }



    };
    // add a component which reports a content-related min
    JLabel label = new JLabel("Welcome to my application!");
    // make it a big min
    label.setFont(label.getFont().deriveFont(40f));
    frame.add(label); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
person kleopatra    schedule 05.01.2012
comment
bump +1 Я голосую за такой разный и ценный ответ, невероятно, пожалуйста, продолжайте с тем же уровнем упорства, что и ваш ответ. - person mKorbel; 06.01.2012