Должен ли я избегать использования методов set (Preferred | Maximum | Minimum) в Java Swing? - программирование
Подтвердить что ты не робот

Должен ли я избегать использования методов set (Preferred | Maximum | Minimum) в 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?
4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

  • Если ответ на вопрос 4 "да", не приведет ли это к разрастанию классов LayoutManager, которые станут трудно поддерживать?

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

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

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

Ответ 2

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

  • Не используйте 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 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());
            }
        }
    }
}

Ответ 3

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

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

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

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

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

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

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

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

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

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

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

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

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

Ссылка:

Ответ 4

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

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

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

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

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

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

Ответ 5

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

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

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

Ответ 6

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

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

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

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

Ответ 7

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

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

Ответ 8

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

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

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

К сожалению, Swing не подходит с разумными размерами по умолчанию. Однако вместо того, чтобы устанавливать размеры компонента, лучше OOP опускать ваш собственный компонент с разумными значениями по умолчанию. (В этом случае вы вызываете 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 находился на двух дисплеях на мульти-дисплей).

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

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

Ответ 9

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

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

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

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

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

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