Categories
java layout-manager swing

Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

502

Several times I’ve been criticized for having suggested the use of the following methods:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

on Swing components. I don’t see any alternative to their use when I want to define proportions between displayed components. I have been told this:

With layouts the answer is always the same: use a suitable
LayoutManager

I have searched the web a little bit, but I haven’t found any comprehensive analysis of the subject. So I have the following questions:

  1. Should I completely avoid the use of those methods?
  2. The methods have been defined for a reason. So when should I use them? In which context? For what purposes?
  3. What exactly are the negative consequences of using those methods? (I can only think adding portability between systems with different screen resolution).
  4. I don’t think any LayoutManager can exactly satisfy all desired layout needs. Do I really need to implement a new LayoutManager for every little variation on my layout ?
  5. If the answer to 4 is “yes”, won’t this lead to a proliferation of LayoutManager classes which will become difficult to maintain?
  6. In a situation where I need to define proportions between children of a Component (eg, child1 should use 10% of space, child2 40% ,child3 50%), is it possible to achieve that without implementing a custom LayoutManager?

0

    245

    1. Should I completely avoid the use of those methods?

      Yes for application code.

    2. The methods have been defined for a reason. So when should I use them? In which context? For what purposes?

      I don’t know, personally I think of it as an API design accident. Slightly forced by compound components having special ideas about child sizes. “Slightly”, because they should have implemented their needs with a custom LayoutManager.

    3. What exactly are the negative consequences of using those methods? (I can only think adding portability between systems with different screen resolution.)

      Some (incomplete, and unfortunately the links are broken due to migration of SwingLabs to java.net) technical reasons are for instance mentioned in the Rules (hehe) or in the link @bendicott found in his/her comment to my answer. Socially, posing tons of work onto your unfortunate fellow who has to maintain the code and has to track down a broken layout.

    4. I don’t think any LayoutManager can exactly satisfy all desired layout needs. Do I really need to implement a new LayoutManager for every little variation on my layout?

      Yes, there are LayoutManagers powerful enough to satisfy a very good approximation to “all layout needs”. The big three are JGoodies FormLayout, MigLayout, DesignGridLayout. So no, in practice, you rarely write LayoutManagers except for simple highly specialized environments.

    5. If the answer to 4 is “yes”, won’t this lead to a proliferation of LayoutManager classes which will become difficult to maintain?

      (The answer to 4 is “no”.)

    6. In a situation where I need to define proportions between children of a Component (for example, child 1 should use 10% of space, child 2 40%, child 3 50%), is it possible to achieve that without implementing a custom LayoutManager?

      Any of the Big-Three can, can’t even GridBag (never bothered to really master, too much trouble for too little power).

    12

    • 5

      I’m not entirely sure I agree with this advice in at least two situations. 1) Custom rendered components 2) Using a JEditorPane with HTML that does not itself suggest a width. OTOH I am not sure if I’ve missed something. I’ll carefully review the replies on the thread, but was interested if you had any comments, particularly on the latter case.

      Aug 30, 2011 at 0:18

    • 2

      @Andrew Thompson 1) custom comps: it’s the comp itself that’s responsible for returning useful layout hints, if they dont the impl is buggy 2) even core comps are buggy 😉 3) I dont mind white space (though it wasn’t intentional this time, thanks 🙂

      – kleopatra

      Aug 30, 2011 at 8:02

    • 14

      I can’t believe the accepted answer is the one that says to avoid using the setXXX() methods. Sometimes you simply need them to provide a hint to the layout manager. If you are laying out a panel then you should absolutely feel free to use these methods when necessary. Saying that I think if you use the appropriate layout manager you will find yourself not needing these methods very often, but on occasion you simply need them. Try putting a JComboBox or JSpinner in a X_AXIS BoxLayout and not use them, believe you will find you need setMaximumSize() there.

      – Michael

      Jul 9, 2013 at 14:07


    • 5

      @Michael no, I absolutely don’t need it – the answer is always to use a decent LayoutManager and do any fine-tweaking on the manager level (vs. the component-level)

      – kleopatra

      Jul 9, 2013 at 14:14

    • 8

      You keep saying “use a decent LayoutManager and tell it what sizes you want” all over stackoverflow, but you never give any specific examples of a “decent” LayoutManager. And none of the standard managers permit controlling the sizes directly.

      – Ti Strga

      Mar 7, 2014 at 19:36

    107

    +100

    A few heuristics:

    • Don’t use set[Preferred|Maximum|Minimum]Size() when you really mean to override get[Preferred|Maximum|Minimum]Size(), as might be done in creating your own component, shown here.

    • Don’t use set[Preferred|Maximum|Minimum]Size() when you could rely on a component’s carefully overridden getPreferred|Maximum|Minimum]Size, as shown here and below.

    • Do use set[Preferred|Maximum|Minimum]Size() to derive post-validate() geometry, as shown below and here.

    • If a component has no preferred size, e.g. JDesktopPane, you may have to size the container, but any such choice is arbitrary. A comment may help clarify the intent.

    • Consider alternate or custom layouts when you find that you would have to loop through many components to obtain derived sizes, as mentioned in these comments.

    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());
                }
            }
        }
    }
    

    9

    • 2

      disagree (as you might have guessed 🙂 with reasoning by “external factors”: the XXSize properties is meant to express internal only needs. Tweaking those from the outside is mis-using, aka hacking. If you want a (Internal- or J-) frame with a a specifc size relative to it’s preferred … size the frame, not the content

      – kleopatra

      Aug 29, 2011 at 12:07

    • 2

      @kleopatra: just to be a little bit insistent: if setXXSize methods should never been used from outside, why haven’t been declared private or protected? Isn’t this a lack of design? Doesn’t the public modifier implicitly tell the user that can use those methods?

      – Heisenbug

      Aug 29, 2011 at 12:12

    • 3

      I have to agree with @kleopatra: setPreferredSize() always replaces the component’s calculation with an arbitrary choice.

      – trashgod

      Aug 29, 2011 at 15:29

    • 2

      @trashgod +100 to you I think there is no problem with overriding these methods, even calling them (but of course this would mean you have a custom component thus overriding would be better)

      Oct 4, 2012 at 12:43

    • 7

      @DavidKroukamp: Thank you. I defer to kleopatra’s greater experience, but I see the value in examining the contrary view critically.

      – trashgod

      Oct 4, 2012 at 15:42

    52

    Should I completely avoid the use of those methods?

    No, there is no formal evidence to suggest calling or overriding these methods is not allowed. In fact, Oracle says these methods are used for giving size hints: http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment.

    They may also be overridden (which is the best practice for Swing) when extending a Swing component (rather than calling the method on the custom component instance)

    Most importantly no matter how you specify your component’s size, be sure that your component’s container uses a layout manager that respects the requested size of the component.

    The methods have been defined for a reason. So when should I use them?
    In which context? For what purposes?

    When you need to provide customized size hints to the containers Layout manager so that the component will be laid out well

    What exactly are the negative consequences of using those methods? (I
    can only think to add portability between systems with different
    screen resolution).

    • Many layout managers do not pay attention to a component’s requested maximum size. However, BoxLayout and SpringLayout do. Furthermore, GroupLayout provides the ability to set the minimum, preferred or maximum size explicitly, without touching the component.

    • Make sure that you really need to set the component’s exact size. Each Swing component has a different preferred size, depending on the font it uses and the look and feel. Thus having a set size might produce varied looks of the UI on different Systems

    • sometimes problems can be encountered with GridBagLayout and text fields, wherein if the size of the container is smaller than the preferred size, the minimum size gets used, which can cause text fields to shrink quite substantially.

    • JFrame does not enforce overriden getMinimumSize() only calling setMinimumSize(..) on its works

    I don’t think any LayoutManager can exactly satisfy all desired layout
    needs. Do I really need to implement a new LayoutManager for every
    little variation on my layout?

    If by implementing you mean using then yes. Not one LayoutManger can handle everything, each LayoutManager has its pros and cons thus each can be used together to produce the final layout.

    Reference:

    5

    • 3

      provide customized size hints that’s a contradiction in itself: providing sizing hints (in px!) is the exclusive task of the component. It calculates them based on internal state details that no other party except itself can know (nor can keep track of). From client perspective, the means of customization can be a suitable LayoutManager and/or specialize api on the component that allows configuring size requirements in terms of “semantic” size-relevant properties, f.i. number of rows/columns in a text component

      – kleopatra

      Oct 1, 2012 at 8:00

    • 4

      @kleopatra I would still love to know why Oracle then tells us how to use these methods and the correct way to use them. We might have our own preferences but we cant say the designers ment it to not be used when there is no evidence to suggest this. But thats why I put up the bounty see maybe if it would attract others that could give a information from a credible source where oracle states to not use these methods at all (thus making it bad practice if you do, for example setMinimumSize has to be called on things like JSplitPane etc this can be seen in the Oracle tutorial of split panes.

      Oct 1, 2012 at 8:06


    • 4

      @David: I’ve come to see the setXxxSize methods as a red flag that I’m may wind up here, even when the docs suggest it. I almost always should have overridden getXxxSize, where one has access to the required geometry; and even short examples get recycled more than I want to think about. +1 for mentioning variation among layout managers and citing the tutorial.

      – trashgod

      Oct 1, 2012 at 20:58

    • 1

      D’oh, in my comment above, I meant to cite the answer here.

      – trashgod

      Oct 4, 2012 at 15:28

    • 16

      +1 “No, there is no formal evidence to suggest calling or overriding these methods is not allowed.” Spot on. The post tagged as answer is plain BS.

      – TT.

      Jun 6, 2013 at 12:31