Why is my JTextArea overflowing a frame in GroupLayout?

I am observing some strange behavior using GroupLayout. I have a JTextArea that is contained inside a JScrollPane that resizes and forces other components out of the JFrame. Oddly enough, if I rebuild the layout so that JTextArea has nothing higher or lower (no spaces), it works fine. It is as if the text area requests the container how much space is in the container, and then takes 100% of it, regardless of other components. Another strange thing is that it only appears when the size of the JTextArea (not the JScrollPane) plus the other component heights inside the container reach Short.MAX_VALUE.

If I specify the maximum size in the vertical group for the scroll bar (when adding a component to the layout) to a value smaller than Short.MAX_VALUE, this seems to fix the problem (while the difference between the value and Short.MAX_VALUE is greater than the height of all other components). eg

.addComponent(textArea, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE - 500)

Also, if I set the preferred size to a small positive value and instead of GroupLayout.PREFERRED_SIZE or GroupLayout.DEFAULT_SIZE, it looks like this behavior will disappear. eg

.addComponent(textArea, 0, 1, Short.MAX_VALUE)

GroupLayout Java tutorials do not seem to mention this and tend to use Short.MAX_VALUE throughout. I tried Google to find the answer, but I found this problem very difficult to describe in search terms.

I found a mistake or just do not understand GroupLayout? The latter certainly seems more likely.

In this example, a simple text area will be created. Click the bottom button to fill it with text (and resize the JTextArea inside the JScrollPane). You can then click inside the text area and add or remove lines. After adding extra lines, click the redraw button (or resize the frame) to see the odd behavior.

 public class GroupLayoutTest { public GroupLayoutTest() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { final JFrame frame = new JFrame("GroupLayout test"); Container panel = frame.getContentPane(); GroupLayout layout = new GroupLayout(panel); panel.setLayout(layout); JButton addBtn = new JButton("Add Lines"); JButton redrawBtn = new JButton("Redraw"); final JTextArea textArea = new JTextArea(); final JScrollPane textPane = new JScrollPane(textArea); layout.setHorizontalGroup(layout.createParallelGroup() .addComponent(redrawBtn) .addComponent(textPane) .addComponent(addBtn)); layout.setVerticalGroup(layout.createSequentialGroup() .addComponent(redrawBtn) .addComponent(textPane) .addComponent(addBtn)); addBtn.addActionListener(new ActionListener() { int m = 0; @Override public void actionPerformed(ActionEvent e) { for (int i = m; m < i + 2044; ++m) { textArea.append("Line " + m + "\n"); } // redraw the frame frame.validate(); } }); redrawBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { frame.validate(); } }); frame.setPreferredSize(new Dimension(640, 480)); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public static void main(String[] args) { new GroupLayoutTest(); } } 
+4
source share
2 answers

I am not familiar with GroupLayout, this is what I observed while looking at documents and thinking about it. Hope this will be helpful. My answer was long, so I will summarize:

Why is this happening? A combination of 3 things.

  • GroupLayout takes into account the preferred size of your components. (why did you choose it, judging by your comments).
  • Your vertical group is consistent. He puts one component at a time - in their preferred size, or more if there is room.
  • Your JScrollPane has an unlimited preferred size. It grows no matter what the preferred size of JTextArea ... leaves no room for the component below it, as soon as its preferred size becomes larger than your frame.

Aligning the layout manager, which refers to the preferred size with a component with a very large preferred size, usually always causes this problem. I have not tested extensively, but I know that this also happens in FormLayout (if you tell it to use the preferred size).

A longer attempt to explain / think:

It is as if the text area is asking the container how much space is in the container, and then taking 100% of it, regardless of other components.

The text area does not ask the container how large it can be - it's the other way around - it tells the container how much it wants to be. In this case, textArea is directly contained in the scroll pane. The preferred size of the text area will grow with the size of the text in the text area. The size of the preferred size of the scroll bar will grow with the preferred size of the text area, unless you set the preferred size in the scroll bar. From there, the planning manager is about to decide how to do this.

In this case, you are using GroupLayout with a SequentialGroup for vertical layout. This will arrange the components in order based on their minimum / maximum / maximum sizes. If you move the text panel as the last element in the group, it will not steal space from your other components ... therefore I assume that for very large sizes GroupLayout does not care if all components are displayed - if there is no space left after the last component, they are not displayed until the container is enlarged. For small sizes, users can adjust the size of the frame ... but for large sizes, for example, in your example, this is not possible.

Apart from the omission, it looks like a combination of a huge scrollbar, and GroupLayout doesn't know when to stop ... so the bottom of the scrollbar bar is turned off. This can be avoided by simply setting a reasonable preferred size on the JScrollPane, though, as @camickr suggested.

Another strange thing is that it appears only when JTextArea (not JScrollPane), plus another element height in the container reaches Short.MAX_VALUE.

If you register the sizes of all components, you will see that if you do not specify a preferred size for JScrollPane, it will always have a preferred size other than the textArea, so I do not think the above statement is true. The size of the scroll pane, plus other components in the container, will still exceed Short.MAX_VALUE and seem to cause problems in GroupLayout, that's true.

The point of the JScrollPane, as I see it, is to place the component with a large (or potentially large) preferred size in a limited, smaller area (with corresponding scrollbars). Then you can always let scrollpane increase the size in excess of its preferred size ... but it starts by telling the scrollbar how big it is. In fact, setting the preferred size effectively tells JScrollPane when it needs scrollbars. For example, if the preferred size of the scroll pane is 400,300, then whenever the preferred width of the contained component exceeds 400 (or the size of the scroll pane, if it is in a container that allows it to grow larger than its preferred size), show the horizontal scrollbars . Likewise for height. Otherwise, it will always grow to the size of what you have, and it won’t need scrollbars to exclude a point or, in some cases, prevent other components from showing.

The docs for GroupLayout mention that they are usually used by other means of the layout linker and not by the developers (although you can still). I would consider using a different layout over the one that usually requires you to use special maximum values ​​to work properly. My personal favorite, FormLayout, is a free third-party layout manager for a BSD license. I don’t think you will ever need to specify fixed sizes for regular components, but in the case of scroll windows you want to give it a preferred size in layouts that respect the preferred size.

I want all my layouts to respect DPI, develop where necessary, and work perfectly with internationalization (where the length of the text can be very different) ... so I would not want to use anything that requires you to specify fixed sizes for everything . I think that in most layouts, setting a fixed preferred size on the scroll bar is not bad. There is not much to do this on a button, text box, or other component that obviously has an obvious preferred size.

Here's what it will look like in FormLayout (it also has assemblers, but in this case I use cell constraints to easily split the column):

 FormLayout layout = new FormLayout( "pref,fill:pref:grow", // cols "pref,3dlu,fill:pref:grow,3dlu,pref" // rows ); JPanel panel = new JPanel(layout); CellConstraints cc = new CellConstraints(); panel.add(redrawBtn, cc.xy(1, 1)); panel.add(textPane, cc.xyw(1, 3, 2)); // span 2 columns panel.add(addBtn, cc.xy(1, 5)); frame.setContentPane(panel); 
+2
source

I do not know the internal elements of GroupLayout, but usually you need to specify the preferred size of the textArea / scrollpane command in order to provide the layout manager with some information to work with. This is done using:

 final JTextArea textArea = new JTextArea(10, 30); 

or

 textPane.setPreferredSize( new Dimension(400, 200) ); 

Otherwise, I believe that the preferred size is basically the size of all the text added to the text area.

+1
source

All Articles