4

I'm trying to create a JPanel that uses the FlowLayout. This panel is placed inside of a container using BorderLayout. This container is then added to a card using CardLayout. I would like the panel using FLowLayout ot be a small box in the bottom left corner of the BorderLayout panel. How would I do this? I've used settingsPanel.setPreferredSize(new Dimension(10, 425)); but the width still spans across the whole panel no matter what size I set, although the height changes. How would I get the width to change?

Code:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;

public class Main {
    //Settings Panel variables
    JLabel settingsTitle = new JLabel("Settings");

    public Main()
    {
        JPanel mainCard = new JPanel(new BorderLayout(8,8));
        JPanel settingsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        settingsTitle.setFont(new Font("TimesRoman", Font.PLAIN, 35));
        settingsPanel.add(settingsTitle);

        final CardLayout layout = new CardLayout();
        final JPanel cards = new JPanel(layout);
        cards.add(mainCard, "2");

        mainCard.add(settingsPanel, BorderLayout.SOUTH);

        settingsPanel.setPreferredSize(new Dimension(10, 425));
        settingsPanel.setBorder(BorderFactory.createLineBorder(Color.black));

        layout.show(cards, "1");

        JFrame window = new JFrame("Test");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.getContentPane().add(cards);
        window.setSize(1280, 720);
        window.setLocationRelativeTo(null);
        window.setResizable(false);
        window.setVisible(true);

    }

    public static void main(String[] args)
    {

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Main();
            }
        });

    }
}

Example:

enter image description here

Saikiran Gosikonda
  • 928
  • 1
  • 11
  • 29
  • 1
    +1 for [Minimal, Complete, Tested and Readable example](http://stackoverflow.com/help/mcve). It makes test easier and answers come faster. – dic19 Feb 26 '14 at 21:34
  • Thanks, I made sure it was formatted correctly this time. Apologies for last time. –  Feb 26 '14 at 21:47

2 Answers2

2

So here's your code changing the BorderLayout with GridBagLayout. The core idea of the GridBagLayout is that you'll have a grid with several rows and columns (of different sizes) and you can place components in each cell. The neat thing about it is that it's very powerful: when you place a component in a cell you can customize the following:

  • How many cells can it span through (vertically, horizontally or both) (gridwidth/gridheight)
  • Where in the cell to put it on: center, top-left, bottom-right... (anchor)
  • The weight of each row/column, this is how much space, proportionally, do they eat when resizing/distribuiting the window. (weightx, weighty)
  • Whether they have to occupy the maximum or the minimum space necessary. (fill)

Among other things. The last point was your problem here, BorderLayout was forcing your panel to expand as much as it could. In my code I used fill = NONE and set it at the anchor = LAST_LINE_START so it stays at the bottom left and doesn't expand.

You can play with these parameters, all the info is in the tutorial. The key to all of it is to know how is your grid. In this example it's very simple it's just a 1x1. But look at the tutorial: those images with a grid painted in red over them, that's what you have to have in your mind. Other than that and knowing all the variables the only tricky thing is how weights work.

    import java.awt.BorderLayout;
    import java.awt.CardLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.Font;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;

    import javax.swing.BorderFactory;
    import javax.swing.BoxLayout;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;    
    public class Main {
    //Settings Panel variables
    JLabel settingsTitle = new JLabel("Settings");

    public Main()
    {
        JPanel mainCard = new JPanel(new GridBagLayout());
        JPanel settingsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        settingsTitle.setFont(new Font("TimesRoman", Font.PLAIN, 35));
        settingsPanel.add(settingsTitle);

        final CardLayout layout = new CardLayout();
        final JPanel cards = new JPanel(layout);
        cards.add(mainCard, "2");

        GridBagConstraints c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 0;
        c.weightx = 1.0;
        c.weighty = 1.0;
        c.anchor = GridBagConstraints.LAST_LINE_START;
        c.fill = GridBagConstraints.NONE; //uneeded line because it's the default value, but it has to be NONE

        mainCard.add(settingsPanel, c);

       // settingsPanel.setPreferredSize(new Dimension(300, 425)); //the components inside settingsPanel will set its side
        settingsPanel.setBorder(BorderFactory.createLineBorder(Color.black));

        layout.show(cards, "1");

        JFrame window = new JFrame("Test");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.getContentPane().add(cards);
        window.setSize(1280, 720); ///replace with window.pack()
        window.setLocationRelativeTo(null);
        window.setResizable(false);
        window.setVisible(true);

    }

    public static void main(String[] args)
    {

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Main();
            }
        });

    }
}
DSquare
  • 2,458
  • 17
  • 19
  • [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). Yes, you should. Components positioning and sizing are layout managers tasks. Please see the link. The answer was written by a really Swing expert. – dic19 Feb 26 '14 at 22:10
  • @dic19 Absolutely, forgot to delete it since it was in his original code. The components inside the settingPanel will define its size appropiately. You can use it to see how would it look like momentarily though. – DSquare Feb 26 '14 at 22:14
  • +1 for the edit. Still need replace `window.setSize(1280, 720)` by `window.pack()`. Just a side note: JFrame's content pane default layout manager is `BorderLayout`. So this line: `window.getContentPane().add(cards);` is actually adding `cards` panel into a container which uses `BorderLayout` ;) – dic19 Feb 26 '14 at 22:16
  • I finally got a chance to look at this, I understand it all, other than the `GridBagConstraints c = new GridBagConstraints`. Do I apply `c` to each panel or what? what does this do, how does it work, etcetera. –  Feb 28 '14 at 18:34
  • @HarryKitchener When you add a component to a container you have to use the method [add(component, constraints)](http://docs.oracle.com/javase/7/docs/api/java/awt/Container.html). You have to give him a component and an object representing the constraints. What class of object is actually constraints depends on the layout of that container. With BorderLayout it's a string indicating NORTH, EAST... For the GridBagLayout constraints is of the class GridBagConstraints. It's the object that gives all the information about how/where to add the component in the container. – DSquare Feb 28 '14 at 18:49
  • 1
    @HarryKitchener Whenever you use add(component) without constraints you are just telling the container to use the default constraints. For example for the BorderLayout it's "CENTER". Or the GridLayout doesn't need constraints because he already knows where to put the components, following the grid defined in the constructor. This is not the case for the GridBagLayout, you always need to put constraints, notice how in all my adds I attach c as the second parameter. `container.add(component, c)` – DSquare Feb 28 '14 at 18:51
  • Also, I'm trying to move the component now, how would I go about doing this? –  Feb 28 '14 at 18:53
  • Depends on where do you want to move it and what else in the panel is there. In my code the component is where it is because the grid of the GridBagLayout is just a 1x1 grid: a big cell containing all the panel. Note that the grid of a GridBagLayout is not initialized it just "grows" as you put components with a certain gridx, gridy. Then I put the settings panel in the bottom left of the cell (0, 0). (The only cell of the grid). You can use another anchor to move it around this big cell. or you can put other components in other cells and then you can move the settings to other cells. – DSquare Feb 28 '14 at 18:58
1

First of all get rid of this: settingsPanel.setPreferredSize(new Dimension(10, 425)) and let the layout managers do their job.

The easiest way I can think about is just wrap settingsPanel inside a different panel and add this last one to the SOUTH:

 JPanel wrapPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
 wrapPanel.add(settingsPanel);

 JPanel mainCard = new JPanel(new BorderLayout(8,8));
 mainCard.add(wrapPanel, BorderLayout.SOUTH); // add wrapPanel here instead of settingsPanel

This way you can take advantage of the FlowLayout property to fill the lesser space it needs:

enter image description here

Really off-topic but I think it's worth

As I've already comment in your previous question this panels thing makes me remember this Portal 2: Panels video. We also need some time to laugh, don't you think?

Community
  • 1
  • 1
dic19
  • 17,821
  • 6
  • 40
  • 69
  • 1
    This is right but it's just a way to work around the real problem: the BorderLayout, I'd suggest changing it for a GridBagLayout, specially if you need to put more components with non trivial placements like this one. – DSquare Feb 26 '14 at 21:39
  • 1
    Agree with @DSquare. Your UI (at least the piece we can see) is not laid out in a "border" style. So avoid using `BorderLayout`. Most of the layout managers in Swing were meant to solve specific, common UI layouts. (`FlowLayout` for button bars, `BorderLayout` for UI's with a main content area, etc.) `GridBagLayout` is the catch all, most flexible one to solve requirements that don't fit neatly into the other layouts. – matt forsythe Feb 26 '14 at 21:43
  • Thanks for the advice. I've looked at GridBagLayout before but really was confused about it. Care to explain? –  Feb 26 '14 at 21:48
  • 1
    @HarryKitchener I'll post an answer using a GridBagLayout in a moment then. – DSquare Feb 26 '14 at 21:49
  • I wouldn't say there's a problem, is just the way on how `BorderLayout` works. IMHO `GridBagLayout` isn't the best option either, too much troubles and not too much power. There are better choices on [DesignGridLayout](https://designgridlayout.java.net/), [MigLayout](http://www.miglayout.com/) or [FormLayout](http://www.jgoodies.com/freeware/libraries/forms/). In any case a [Nested Layout](http://stackoverflow.com/questions/5621338/how-to-add-jtable-in-jpanel/5630271#5630271) approach is not a bad idea at all. @DSquare – dic19 Feb 26 '14 at 21:53
  • @mattforsythe if I remember right OP's is trying to do some kind of wizzard with buttons at the bottom and a main content placed in the center. Check his [previous question](http://stackoverflow.com/questions/21947493/jframe-gridbaglayout-component-positioning). So, yes, it's a "border" style. – dic19 Feb 26 '14 at 21:59
  • @dic19, no, this is a different kind of application. –  Feb 26 '14 at 22:15