0

I am trying to create a simple Java Swing GUI that consists of a panel on top and tabs in the center. I want the top panel to remain its preferred size and the tabs to take up the remaining space so I used a BorderLayout. The content of the tab can be tall so I put the tab component into a scroll pane.

Everything seems to work the way I expect (with respect to component sizing and scroll bar behavior when I resize the frame) except that my packed frame is 12 pixels too tall (and possibly 16 pixels too wide). Would someone please explain what is going on and how to resolve it. Somehow when the pack is sizing all of the components, something is smart enough to (mostly) respect the screen size. I am using Java 8 on Windows 7 with a screen resolution of 1920 x 1200.

Below is my test code and the output it produces.

Code:

package test;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;

public final class SizeTest
{
    public static void main(final String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGui();
            }
        });
    }

    private static void createAndShowGui()
    {
        final JPanel topPanel = new JPanel();
        topPanel.setBorder(BorderFactory.createTitledBorder("Top"));
        topPanel.setPreferredSize(new Dimension(800, 150));

        final JPanel centerPanel = new JPanel();
        centerPanel.setBorder(BorderFactory.createTitledBorder("Center"));
        centerPanel.setPreferredSize(new Dimension(800, 1300));

        final JScrollPane scrollPane = new JScrollPane(centerPanel);

        final JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.addTab("Tab", scrollPane);

        final JPanel mainPanel = new JPanel(new BorderLayout(0, 10));
        mainPanel.add(topPanel, BorderLayout.NORTH);
        mainPanel.add(tabbedPane, BorderLayout.CENTER);

        final JFrame mainFrame = new JFrame("Size Test");
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.add(mainPanel);
        mainFrame.pack();

        System.err.println("***** Frame Size: " + mainFrame.getSize() + ", Screen Size: "
            + Toolkit.getDefaultToolkit().getScreenSize() + ", Maximum Window Bounds: "
            + GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds());

        mainFrame.setVisible(true);
    }
}

Output:

***** Frame Size: java.awt.Dimension[width=816,height=1212], Screen Size: java.awt.Dimension[width=1920,height=1200], Maximum Window Bounds: java.awt.Rectangle[x=0,y=0,width=1920,height=1156]
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
V3V
  • 107
  • 5
  • 1
    *"centerPanel.setPreferredSize(new Dimension(800, 1300));"* might be an issue – MadProgrammer Apr 21 '17 at 11:54
  • The way I figure it, height of first panel 150 + 10 layout padding + 1300 for lower panel + **frame chrome at top & bottom** is 1460 + frame chrome which is larger than the screen height. Once a GUI goes to those lengths (or rather heights), the OS is likely to ***enforce*** a more sensible size on it, and all bets are off. How does the same experiment play out with a frame that is *shorter* than the screen height? – Andrew Thompson Apr 21 '17 at 12:06
  • 1
    I retried the experiment with 300 instead of 1300 for the center panel and the window size becomes 816x518. Based on your math from above, that would indicate that the frame chrome is 58 pixels. I think this means your theory is probably correct about something (likely the OS as you stated) clipping the window height to something more reasonable – V3V Apr 21 '17 at 12:36
  • Tip: Add @MadProgrammer (or whoever, the `@` is important) to *notify* the person of a new comment. – Andrew Thompson Apr 22 '17 at 01:22

1 Answers1

0

If you're going to stuff around with setPreferredSize, be prepared for things to go astray.

The first thing I would do, is seriously reconsider using setPreferredSize.

Because of the way the API works, JScrollPane will use the preferredSize of the component to make determinations about it's own size. You can change this by implementing the Scrollable interface, which allows you to return the preferredScrollableViewportSize, which JScrollPane will use instead when determing how large it needs to be

You see Scrollable demonstrated here and here and lots of other places if you do some searching

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Do you mean reconsider using `setPreferredSize` in general or specifically in the case of the center panel? In my test program, I used that as a shortcut to achieving something that matched my real life case. I tried replacing that code with a loop that adds 100 labels to the center panel (using a 100x1 grid layout) and got the same result (i.e. never using `setPreferredSize` – V3V Apr 21 '17 at 12:41
  • 1
    [Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?](http://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi) - In general, yes, it's not your responsibility to determine this, it's the components. Did you implement the `Scrollable` interface? Did you return a desirable size from `preferredScrollableViewportSize`? – MadProgrammer Apr 21 '17 at 22:05
  • I was afraid that returning a size from `preferredScrollableViewPortSize` would create a fixed size viewport. However after experimenting with the example you linked to originally, it seems to just be a starting point. When I resize the frame, the scroll pane stretches appropriately the way I wanted originally. Thank you for your assistance – V3V Apr 24 '17 at 10:49