Следует ли мне избегать использования методов set(Preferred|Maximum|Minimum)Size в Java Swing?

Несколько раз меня критиковали за то, что я предложил использовать следующие методы:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

на Swing компоненты. Я не вижу альтернативы их использованию, когда я хочу определить пропорции между отображаемыми компонентами. Мне сказали это:

С макетами ответ всегда один и тот же: используйте подходящий LayoutManager

Я немного искал в Интернете, но я не нашел никакого всестороннего анализа предмета. Итак, у меня есть следующие вопросы:

  1. Должен ли я полностью избегать использования этих методов?
  2. Методы были определены по причине. Так, когда я должен использовать их? В каком контексте? Для каких целей?
  3. Каковы конкретно негативные последствия использования этих методов? (Я могу только подумать о добавлении переносимости между системами с разным разрешением экрана).
  4. Я не думаю, что любой LayoutManager может точно удовлетворить все желаемые потребности макета. Действительно ли мне нужно реализовывать новый LayoutManager для каждого небольшого изменения моего макета?
  5. Если ответ на 4 "да", не приведет ли это к увеличению числа классов LayoutManager, которое будет трудно поддерживать?
  6. В ситуации, когда мне нужно определить пропорции между дочерними элементами компонента (например, child1 должен использовать 10% пространства, child2 40%,child3 50%), возможно ли достичь этого без реализации пользовательского LayoutManager?

9 ответов

Решение
  1. Должен ли я полностью избегать использования этих методов?

    Да, для кода приложения.

  2. Методы были определены по причине. Так, когда я должен использовать их? В каком контексте? Для каких целей?

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

  3. Каковы конкретно негативные последствия использования этих методов? (Я могу только подумать о добавлении переносимости между системами с разным разрешением экрана.)

    Некоторые (неполные, и, к сожалению, ссылки не работают из-за миграции SwingLabs на java.net) технические причины, например, упоминаются в Правилах (хе-хе) или в ссылке @bendicott, найденной в его / ее комментарии к моему ответу. В социальном плане, излагая тонны работы на вашего несчастного товарища, который должен поддерживать код и выискивать сломанный макет.

  4. Я не думаю, что любой LayoutManager может точно удовлетворить все желаемые потребности макета. Действительно ли мне нужно реализовывать новый LayoutManager для каждого небольшого изменения моего макета?

    Да, есть LayoutManager, достаточно мощный, чтобы удовлетворить очень хорошее приближение ко всем потребностям макета. Большая тройка - это JGoodies FormLayout, MigLayout, DesignGridLayout. Так что нет, на практике вы редко пишете LayoutManager, за исключением простых узкоспециализированных сред.

  5. Если ответ на 4 "да", не приведет ли это к увеличению числа классов LayoutManager, которое будет трудно поддерживать?

    (Ответ на 4 - "нет".)

  6. В ситуации, когда мне нужно определить пропорции между дочерними элементами компонента (например, дочерний элемент 1 должен использовать 10% пространства, дочерний элемент 2 40%, дочерний элемент 3 50%), возможно ли достичь этого без реализации пользовательского LayoutManager?

    Любой из Большой тройки может, даже не может GridBag (никогда не удосужился по-настоящему освоить, слишком много проблем для слишком малой мощности).

Несколько эвристик:

  • Не использовать set[Preferred|Maximum|Minimum]Size() когда вы действительно хотите переопределить get[Preferred|Maximum|Minimum]Size(), как это может быть сделано при создании собственного компонента, показанного здесь.

  • Не использовать set[Preferred|Maximum|Minimum]Size() когда вы можете положиться на тщательно переопределенный компонент getPreferred|Maximum|Minimum]Size, как показано здесь и ниже.

  • Использовать set[Preferred|Maximum|Minimum]Size() вывести пост-validate() геометрия, как показано ниже и здесь.

  • Если компонент не имеет предпочтительного размера, например JDesktopPaneВозможно, вам придется определить размер контейнера, но любой такой выбор является произвольным. Комментарий может помочь уточнить намерение.

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

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
 * @see https://stackru.com/questions/7229226
 * @see https://stackru.com/questions/7228843
 */
public class DesignTest {

    private List<JTextField> list = new ArrayList<JTextField>();
    private JPanel panel = new JPanel();
    private JScrollPane sp = new JScrollPane(panel);

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

            @Override
            public void run() {
                DesignTest id = new DesignTest();
                id.create("My Project");
            }
        });
    }

    private void addField(String name) {
        JTextField jtf = new JTextField(16);
        panel.add(new JLabel(name, JLabel.LEFT));
        panel.add(jtf);
        list.add(jtf);
    }

    private void create(String strProjectName) {
        panel.setLayout(new GridLayout(0, 1));
        addField("First Name:");
        addField("Last Name:");
        addField("Address:");
        addField("City:");
        addField("Zip Code:");
        addField("Phone:");
        addField("Email Id:");
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .addPropertyChangeListener("permanentFocusOwner",
            new FocusDrivenScroller(panel));
        // Show half the fields
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        sp.validate();
        Dimension d = sp.getPreferredSize();
        d.setSize(d.width, d.height / 2);
        sp.setPreferredSize(d);

        JInternalFrame internaFrame = new JInternalFrame();
        internaFrame.add(sp);
        internaFrame.pack();
        internaFrame.setVisible(true);

        JDesktopPane desktopPane = new JDesktopPane();
        desktopPane.add(internaFrame);

        JFrame frmtest = new JFrame();
        frmtest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmtest.add(desktopPane);
        frmtest.pack();
        // User's preference should be read from java.util.prefs.Preferences
        frmtest.setSize(400, 300);
        frmtest.setLocationRelativeTo(null);
        frmtest.setVisible(true);
        list.get(0).requestFocusInWindow();
    }

    private static class FocusDrivenScroller implements PropertyChangeListener {

        private JComponent parent;

        public FocusDrivenScroller(JComponent parent) {
            this.parent = parent;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            Component focused = (Component) evt.getNewValue();
            if (focused != null
                && SwingUtilities.isDescendingFrom(focused, parent)) {
                parent.scrollRectToVisible(focused.getBounds());
            }
        }
    }
}

Должен ли я полностью избегать использования этих методов?

Нет, нет никаких официальных доказательств того, что использование или переопределение этих методов не допускается. Фактически, Oracle говорит, что эти методы используются для предоставления подсказок по размеру: http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html.

Они также могут быть переопределены (что является наилучшей практикой для Swing) при расширении компонента Swing (вместо вызова метода в экземпляре пользовательского компонента)

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

Методы были определены по причине. Так, когда я должен использовать их? В каком контексте? Для каких целей?

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

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

  • Многие менеджеры компоновки не обращают внимание на максимальный размер запрошенного компонента. Тем не мение, BoxLayout а также SpringLayout делать. Более того, GroupLayout обеспечивает возможность явной установки минимального, предпочтительного или максимального размера, не касаясь компонента.

  • Убедитесь, что вам действительно нужно установить точный размер компонента. Каждый компонент Swing имеет свой предпочтительный размер, в зависимости от используемого шрифта и внешнего вида. Таким образом, наличие установленного размера может привести к различному виду пользовательского интерфейса в разных системах.

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

  • JFrame не применяет переопределение getMinimumSize() только звонит setMinimumSize(..) на своих работах

Я не думаю, что любой LayoutManager может точно удовлетворить все желаемые потребности макета. Действительно ли мне нужно реализовывать новый LayoutManager для каждого небольшого изменения моего макета?

Если под реализацией вы подразумеваете использование, то да. Не один LayoutManger может справиться со всем, каждый LayoutManager имеет свои плюсы и минусы, поэтому каждый из них может быть использован вместе для создания окончательного макета.

Ссылка:

Здесь есть много хороших ответов, но я хочу добавить немного больше о причинах, по которым вам следует избегать их (вопрос только что снова возник в дублирующей теме):

За некоторыми исключениями, если вы используете эти методы, вы, вероятно, настраиваете свой графический интерфейс, чтобы он хорошо выглядел под конкретный внешний вид (и с вашими системными настройками, например, предпочитаемым шрифтом рабочего стола и т. Д.). Сами методы не являются злыми по своей природе, но типичные причины их использования. Как только вы начинаете настраивать позиции и размеры пикселей в макете, вы рискуете сломать графический интерфейс (или, как минимум, выглядеть плохо) на других платформах.

Как пример этого, попробуйте изменить внешний вид вашего приложения по умолчанию. Даже с опциями, доступными на вашей платформе, вы можете быть удивлены тем, насколько плохо могут быть получены результаты.

Таким образом, во имя поддержания функциональности и привлекательности графического интерфейса пользователя на всех платформах (помните, одно из главных преимуществ Java - его кроссплатформенность), вам следует полагаться на менеджеры компоновки и т. Д. Для автоматической настройки размеров ваши компоненты, чтобы он правильно отображался за пределами вашей конкретной среды разработки.

Все это говорит о том, что вы, конечно, можете представить себе ситуации, когда эти методы оправданы. Опять же, они не являются злыми по своей сути, но их использование обычно представляет собой большой красный флаг, указывающий на потенциальные проблемы графического интерфейса. Просто убедитесь, что вы знаете о высокой вероятности возникновения осложнений, если / когда вы их используете, и всегда старайтесь думать о том, есть ли другое решение ваших проблем, не зависящее от внешнего вида - чаще всего вы обнаружите, что это методы не нужны.

Кстати, если вы разочаровались в стандартных менеджерах компоновки, есть много хороших бесплатных сторонних разработчиков с открытым исходным кодом, например, JGoodies ' FormLayout, или же MigLayout, Некоторые сборщики графического интерфейса пользователя даже имеют встроенную поддержку сторонних менеджеров компоновки - например, редактор графического интерфейса пользователя Eclipse WindowBuilder поставляется с поддержкой FormLayout а также MigLayout,

Если у вас возникли проблемы с макетами в Java Swing, тогда я настоятельно рекомендую JGoodies FormLayout предоставляется бесплатно как часть бесплатной библиотеки форм Karsten Lentzsch здесь.

Этот очень популярный менеджер компоновки чрезвычайно гибок, что позволяет разрабатывать очень отлаженные пользовательские интерфейсы Java.

Вы найдете документацию Карстена здесь, и некоторые довольно хорошие документы от затмения здесь.

Эти методы плохо поняты большинству людей. Вы не должны абсолютно игнорировать эти методы. Это зависит от менеджера макета, если они соблюдают эти методы. На этой странице есть таблица, которая показывает, какие менеджеры по компоновке соблюдают какой из этих методов:

http://thebadprogrammer.com/swing-layout-manager-sizing/

Я пишу код Swing уже более 8 лет, и менеджеры по компоновке, включенные в JDK, всегда удовлетворяли мои потребности. Я никогда не нуждался в стороннем менеджере по расположению, чтобы достигнуть моих расположений.

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

В ситуации, когда мне нужно определить пропорции между дочерними элементами компонента (дочерний элемент 1 должен использовать 10% пространства, дочерний2 40%, дочерний 3 50%), возможно ли достичь этого без применения настраиваемого менеджера компоновки?

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

Я вижу это иначе, чем принятый ответ.

1) Должен ли я полностью избегать использования этих методов?

Никогда не избегай! Они там, чтобы выразить ограничения размера ваших компонентов в менеджере макета. Вы можете избежать их использования, если не используете какой-либо менеджер макетов и попробуйте самостоятельно управлять визуальным макетом.

К сожалению, Swing не поставляется с разумными размерами по умолчанию. Однако вместо установки размеров компонента лучше ООП спускать свой собственный компонент с разумными значениями по умолчанию. (В этом случае вы вызываете setXXX в своем классе-потомке.) Кроме того, вы можете переопределить методы getXXX для того же эффекта.

2) Методы были определены по причине. Так, когда я должен использовать их? В каком контексте? Для каких целей?

Всегда. Когда вы создаете компонент, установите его реалистичный минимальный / предпочтительный / максимальный размер в соответствии с использованием этого компонента. Например, если у вас есть JTextField для ввода символов страны, таких как Великобритания, его предпочтительный размер должен быть таким же широким, чтобы соответствовать двум символам (с текущим шрифтом и т. Д.), Но, вероятно, бессмысленно позволять ему расти еще больше. Ведь символы страны - это две буквы. Напротив, если у вас есть JTextField для ввода, например, имени клиента, он может иметь предпочтительный размер, например размер пикселя для 20 символов, но может увеличиваться до большего при изменении размера макета, поэтому установите максимальный размер больше. В то же время наличие JTextField шириной 0px не имеет смысла, поэтому установите реалистичный минимальный размер (я бы сказал, что размер пикселя составляет 2 символа).

3) Каковы конкретно негативные последствия использования этих методов?

(Я могу только подумать о добавлении переносимости между системами с разным разрешением экрана).

Никаких негативных последствий. Это подсказки для менеджера макета.

4) Я не думаю, что любой LayoutManager может точно удовлетворить все желаемые потребности макета.

Действительно ли мне нужно реализовывать новый LayoutManager для каждого небольшого изменения моего макета?

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

Например, макет ниже:

<pre>
+--------------+--------+
| ###JTABLE### | [Add]  | 
| ...data...   |[Remove]|
| ...data...   |        |
| ...data...   |        |
+--------------+--------+
</pre>

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

Конечно, это может быть сложно с реальным макетом жизни. Поэтому менеджеры макетов на основе сетки, такие как MigLayout, намного лучше, если вы собираетесь разрабатывать что-то серьезное.

5) Если ответ на вопрос 4 "да", не приведет ли это к увеличению числа классов LayoutManager, которое будет трудно поддерживать?

Нет, вы определенно не будете разрабатывать менеджеры компоновки, если вам не нужно что-то особенное.

6) В ситуации, когда мне нужно определить пропорции...

между дочерними компонентами (например, child1 должен использовать 10% пространства, child2 40%,child3 50%), возможно ли достичь этого без реализации пользовательского LayoutManager?

Как правило, после того, как предпочтительные размеры установлены правильно, вы можете не захотеть ничего делать в процентах. Просто потому, что проценты не имеют смысла (например, бессмысленно иметь JTextField 10% от размера окна - поскольку можно уменьшить окно, чтобы JTextField стал шириной 0px, или можно расширить окно, чтобы JTextField находился на двух экранах на экране. настройка нескольких дисплеев).

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

Вы можете использовать JSplitPane, где вы можете предварительно установить соотношение двух сторон. Или вы можете использовать MigLayout, который позволяет вам устанавливать такие ограничения в процентах, пикселях и других единицах.

Должен ли я полностью избегать использования этих методов? Я бы не сказал "избегать" их. Я бы сказал, что если вы думаете, что они вам нужны, вы, вероятно, делаете что-то не так. Размеры компонентов определяются в контексте. Например, размеры текстового компонента определяются указанным количеством строк и столбцов в сочетании с выбранным вами шрифтом. Размер вашей кнопки и метки будет соответствовать размеру графического изображения, если вы его установили, или пространству, необходимому для отображения заданного вами текста. Каждый компонент имеет естественный размер, и менеджеры компоновки будут использовать их для разметки всего, без необходимости указывать размеры. Основным исключением является JScrollPane, размер которого не зависит от содержимого. Для тех, я буду иногда звонить setSize() и пусть этот размер определяет начальный размер окна, вызывая JFrame.pack(), Обычно я позволяю размеру окна определять размер JScrollPane. Пользователь определит размер окна. Многие менеджеры по компоновке игнорируют установленные вами размеры, поэтому они часто не приносят пользы.

Методы были определены по причине. Так, когда я должен использовать их? В каком контексте? Для каких целей? Я полагаю, что они были добавлены, чтобы предоставить подсказки менеджерам по расположению. Возможно, они были написаны по историческим причинам, потому что менеджеры по компоновке были новыми, и люди не полностью доверяли им. Я знаю нескольких разработчиков, которые избегали менеджеров компоновки и размещали все вручную только потому, что не хотели беспокоиться о изучении новой парадигмы. Это ужасная идея.

Каковы конкретно негативные последствия использования этих методов? (Я могу только подумать о добавлении переносимости между системами с разным разрешением экрана). Они неэффективны и создают плохие макеты, при этом объекты сжимаются или растягиваются до неестественных размеров. И макеты будут хрупкими. Изменения в размере окна иногда нарушают компоновку и помещают вещи в неправильные места.

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

Если ответ на 4 "да", не приведет ли это к увеличению числа классов LayoutManager, которое будет трудно поддерживать? Если вы реализуете новые классы менеджера компоновки для небольших изменений в компоновке, вы используете их неправильно. Если вы просто внедряете новые менеджеры компоновки, вы, вероятно, делаете что-то не так. Единственный раз, когда я расширил класс LayoutManager, это было добавить ползунок масштабирования в JScrollPane.

В ситуации, когда мне нужно определить пропорции между дочерними элементами компонента (например, child1 должен использовать 10% пространства, child2 40%,child3 50%), возможно ли достичь этого без реализации пользовательского LayoutManager? У JSplitPane есть способ указать процент, который должен получить каждый компонент. По умолчанию разделитель является подвижным, но вы можете отключить его, если хотите. Я не использую эту функцию много. У меня обычно есть некоторые компоненты, которые занимают заданный размер, а остальное пространство занимает область прокрутки. Размер области прокрутки будет регулироваться в зависимости от размера окна. Если у вас есть две панели прокрутки рядом, вы можете поместить их в JSplitPane и указать процент нового пространства, выделяемого каждой из них, когда пользователь расширяет и сжимает окна.

Другие вопросы по тегам