7

Hi everyone I have a JFrame which has three components inside.

  1. A menu
  2. A tabbed pane
  3. a panel that has some buttons

Initially my goal was to create a design like the following: enter image description here

when the user would resize the application, everything would be resized as well. So I thought maybe if I used a simple grid layout my problem would be solved, so I decided to do the following:

  1. The tabbed pane will have some panels inside and those panels will follow the grid layout.

  2. the Panel at the bottom will follow the grid layout.

  3. the JFrame will follow the grid layout as well.

Results:

enter image description here

As you can see this is not what I wanted, the buttons are too big and although the application resizes very well:

enter image description here

The buttons resize as well but they remain too big. I would like to be able to set a small size for the buttons(more specifically the panel they are contained in) and when the user resizes the application, the buttons would resize only horizontally never vertically which means that ONLY the tabbed pane would grow bigger vertically. Is this achievable? I searched and found out about gridbaglayout, I started playing a little bit, but I didn't achieve anything. All I managed to do is the following:

enter image description here

seems good, but when I resize this is what I get:

enter image description here

thanks in advance.

mKorbel
  • 109,525
  • 20
  • 134
  • 319
ksm001
  • 3,772
  • 10
  • 36
  • 57

2 Answers2

13

I would use BorderLayout for the content pane. Put the tabbed pane in it using BorderLayout.CENTER, and the panel of buttons in it using BorderLayout.SOUTH.

splungebob
  • 5,357
  • 2
  • 22
  • 45
  • +1 I think this will work too. Then `setPreferredSize` for the lower panel. That will make its height constant. Don't set size for the center panel. That way everything else maintains a size while only the center expands when you expand the window. Also, the lower panel should use a `FlowLayout`. – davidXYZ Sep 26 '12 at 15:59
  • 1
    @davidXYZ No need to set the preferred size on the lower panel. setting preferred size is the exception! – Guillaume Polet Sep 26 '12 at 16:48
  • @davidXYZ You might like to have a read of [this](http://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi) before you start messing with the pref/max/min sizes – MadProgrammer Sep 26 '12 at 20:21
  • @MadProgrammer I've used what I mentioned here and it works. I've read that other post by the way. Do you have any other suggestion about how to maintain a constant height for a JPanel? – davidXYZ Sep 26 '12 at 20:30
  • @davidXYZ It's a catch 22. The problem with using pref/min/max heights is that you start making assumptions about the font height which won't match across platforms (or even machines). I know the argument "I'm only writing for Windows", but it doesn't change the fact that it generally a bad practice (and the font I use on my Windows box my not be the same you us ;)). The manner in which you fix this will come down to what it is you are try to achieve. From question, I'd err on the side of using an appropriate layout manager. Not every solution fits every problem – MadProgrammer Sep 26 '12 at 22:28
  • @MadProgrammer I agree that a good layoutmgr solves d problem and prevents rigidness. But sometimes, you may just need a constant size for a bar (like when I wanted to have a message bar on my window. I couldnt depend on the `JLabel` displaying the message to give the panel its height bcos sometimes the label is empty and the panel would collapse. I wanted it to always be up and have a definite height. So I did `panel.setPreferredSize(new Dimension(frame.getPreferredSize().width, 30))`. This looks weird but served my purpose. :) ksm001 may have wanted such stuff and thats why i suggested it. – davidXYZ Sep 26 '12 at 22:46
  • @davidXYZ Don't get me wrong, I'm having a go at you, I agree, there are always exceptions to this rule, but you need to know when to use them. You could have create a dummy `JLabel` and used it's preferred height as the part of the return value from `getPreferredSize()` instead, this would have taken into account differences in the font metrics and DPI – MadProgrammer Sep 26 '12 at 22:57
7

the JFrame will follow the grid layout as well.

This is your problem. Instead, use the default BorderLayout (so remove your call that set the layout of the JFrame to a GridLayout) and

  1. Add your button panel with the constraint BorderLayout.SOUTH
  2. Add your tabbed pane without any constraints (which means the constraint BorderLayout.CENTER)

Take a look at the Swing LayoutManager tutorial and in particular, the example that concerns BorderLayout.

Small example:

import java.awt.BorderLayout;
import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;

public class TestLayout {

    protected void initUI() {
        final JFrame frame = new JFrame(TestLayout.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        JMenuItem newItem = new JMenuItem("New...");
        JMenuItem open = new JMenuItem("Open...");
        fileMenu.add(newItem);
        fileMenu.add(open);
        menuBar.add(fileMenu);
        JTabbedPane tabs = new JTabbedPane();
        tabs.addTab("Tab 1", new JPanel());
        tabs.addTab("Tab 2", new JPanel());
        tabs.addTab("Tab 3", new JPanel());
        JPanel buttonPanel = new JPanel(new GridLayout());
        buttonPanel.add(new JButton("Button-1"));
        buttonPanel.add(new JButton("Button-2"));
        buttonPanel.add(new JButton("Button-3"));
        frame.add(tabs);
        frame.add(buttonPanel, BorderLayout.SOUTH);
        frame.setJMenuBar(menuBar);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestLayout().initUI();
            }
        });
    }
}
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117