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

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

  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 ]

236 голосов
/ 29 августа 2011
  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 (никогда не удосужился по-настоящему освоить, слишком много проблем для слишком малой мощности).

99 голосов
/ 29 августа 2011

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

  • Не используйте 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, возможно, вам придется выбрать размер контейнера, но любой такой выбор является произвольным.Комментарий может помочь прояснить намерение.

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

enter image description here

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://stackoverflow.com/questions/7229226
 * @see https://stackoverflow.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());
            }
        }
    }
}
46 голосов
/ 01 октября 2012

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

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

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

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

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

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

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

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

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

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

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

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

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

Ссылка:

25 голосов
/ 10 марта 2014

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

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

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

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

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

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

20 голосов
/ 29 августа 2011

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

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

Документацию Карстена вы найдете в здесь , а также довольно неплохую документацию из eclipse здесь .

16 голосов
/ 25 марта 2013

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

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

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

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

15 голосов
/ 29 августа 2011

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

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

5 голосов
/ 16 февраля 2016

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

0 голосов
/ 18 октября 2018

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

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

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

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

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

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

...