4

As the title said, I'm trying to put 4 different JLabels at each of the corners of a JFrame. I want them to stay there forever even if I try to resize the JFrame

I've tried using a layout manager but I just can't get it right.

    ImageIcon icon;
    JLabel labelNW = new JLabel();
    JLabel labelNE = new JLabel();
    JLabel labelSW = new JLabel();
    JLabel labelSE = new JLabel();
    URL buttonURL = InputOutputTest.class.getResource("images/square_dot.gif");
    if(buttonURL != null){
        icon = new ImageIcon(buttonURL);
        labelNW.setIcon(icon);
        labelNE.setIcon(icon);
        labelSW.setIcon(icon);
        labelSE.setIcon(icon);
    }
    window.add(labelNW, BorderLayout.NORTH);
    //window.add(labelNE, BorderLayout.EAST);
    //window.add(labelSW, BorderLayout.WEST);
    window.add(labelSE, BorderLayout.SOUTH);

This code takes care of the north and south of the left side. I'm probably approaching this wrong though.

I also tried GridLayout (2,2) but they weren't at the corners and there's a huge gap on the right side.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
kir
  • 581
  • 1
  • 6
  • 22

3 Answers3

7

You will want to nest JPanels each using its own layout. In fact you could do this by nesting JPanels that all use BorderLayout.

Going to check if GridBagLayout can do it in one shot.... hang on...

Yep GridBagLayout does it too:

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.*;

public class GridBagExample {
   public static void main(String[] args) {
      JPanel mainPanel = new JPanel(new GridBagLayout());

      GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
            GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(
                  0, 0, 0, 0), 0, 0);
      mainPanel.add(new JLabel("Left Upper"), gbc);

      gbc.gridx = 1;
      gbc.gridy = 0;
      gbc.anchor = GridBagConstraints.NORTHEAST;
      mainPanel.add(new JLabel("Right Upper"), gbc);

      gbc.gridx = 0;
      gbc.gridy = 1;
      gbc.anchor = GridBagConstraints.SOUTHWEST;
      mainPanel.add(new JLabel("Left Lower"), gbc);

      gbc.gridx = 1;
      gbc.gridy = 1;
      gbc.anchor = GridBagConstraints.SOUTHEAST;
      mainPanel.add(new JLabel("Right Lower"), gbc);

      JFrame frame = new JFrame("Test");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.setLocationRelativeTo(null);
      frame.pack();
      frame.setVisible(true);
   }
}

Edit
Now for the BorderLayout example:

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.*;

public class BorderLayoutExample {
   public static void main(String[] args) {
      JPanel northPanel = new JPanel(new BorderLayout());      
      northPanel.add(new JLabel("North East"), BorderLayout.EAST);
      northPanel.add(new JLabel("North West"), BorderLayout.WEST);

      JPanel southPanel = new JPanel(new BorderLayout());
      southPanel.add(new JLabel("South East"), BorderLayout.EAST);
      southPanel.add(new JLabel("South West"), BorderLayout.WEST);


      JPanel mainPanel = new JPanel(new BorderLayout());
      mainPanel.add(northPanel, BorderLayout.NORTH);
      mainPanel.add(southPanel, BorderLayout.SOUTH);

      JFrame frame = new JFrame("BorderLayout Test");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Care to elaborate more or give an example on nesting JPanels? I'm not really sure how that works. – kir Aug 14 '13 at 01:12
  • @user2280704: to nest JPanels you simply put JPanels inside of one another, each using its own layout. Give it a try, you'll be glad you did! – Hovercraft Full Of Eels Aug 14 '13 at 01:14
  • Thanks for the advice. I'll try all these ideas and come back if I have more questions. – kir Aug 14 '13 at 01:17
  • Nesting `JPanel`s is completely unnecessary. See my answer. – durron597 Aug 14 '13 at 01:19
  • `"Going to check if GridBagLayout can do it in one shot..."` I can't remember the last time I answered "no" to this. – splungebob Aug 14 '13 at 01:20
  • @user2280704: nested BorderLayout example as well – Hovercraft Full Of Eels Aug 14 '13 at 01:23
  • Also, I don't particularly like `GridBagLayout` because if you ever want to, say, insert a new component in the middle, you have to change all the x and y values. `GroupLayout` is far easier, in my opinion, to extend. – durron597 Aug 14 '13 at 01:24
  • @durron597: that's why my preference is to use nested layouts. – Hovercraft Full Of Eels Aug 14 '13 at 01:24
  • @HovercraftFullOfEels for complicated composite screens, you can end up with many nested panels, and only some `LayoutManager`s respect Minimum/Preferred/Maximum by default, so your options become limited if you want to let objects size themselves. Ultimately I find the nested panel solution doesn't scale either. – durron597 Aug 14 '13 at 01:26
  • @durron597: when I have complicated composite screens, usually each major section is its own self-contained class. I've not run into layout problems regarding respect of Min/Pref/Max, as long as you know how to use the layout managers properly. I'm sure that your way will work as well as long as the author is well familiar with the tool, and therein lies the key to all of this. – Hovercraft Full Of Eels Aug 14 '13 at 01:29
  • Thanks for the replies guys. I particularly liked the nesting of JPanels, which to me was clean and easier to visualize. Wish I can upvote both but I still need more reps for that. Cheers. – kir Aug 14 '13 at 01:37
  • @user2280704: you'll get rep soon enough. Just remember to come back and upvote durron's answer later (as I have done now). – Hovercraft Full Of Eels Aug 14 '13 at 01:38
5

I find that only GroupLayout gives me the control I need for precisely laid out components. This should do the trick. You need to make sure the gap in between has a very large Maximum value (i.e. Short.MAX_VALUE), but you can set the minimum and preferred sizes to whatever you want.

public class LabelFrame extends JFrame {
    public LabelFrame() {
        JPanel contentPane = new JPanel();
        JLabel labelNW = new JLabel();
        JLabel labelNE = new JLabel();
        JLabel labelSW = new JLabel();
        JLabel labelSE = new JLabel();
        URL buttonURL = InputOutputTest.class.getResource("images/square_dot.gif");
        if(buttonURL != null){
            icon = new ImageIcon(buttonURL);
            labelNW.setIcon(icon);
            labelNE.setIcon(icon);
            labelSW.setIcon(icon);
            labelSE.setIcon(icon);
        }
        GroupLayout layout = new GroupLayout(contentPane);
        layout.setHorizontalGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(Alignment.LEADING)
                        .addComponent(labelNW)
                        .addComponent(labelSW))
                .addGap(20,50,Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(Alignment.TRAILING)
                        .addComponent(labelNE)
                        .addComponent(labelSE))
        );
        layout.setVerticalGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(Alignment.LEADING)
                        .addComponent(labelNW)
                        .addComponent(labelNE))
                .addGap(20,50,Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(Alignment.TRAILING)
                        .addComponent(labelSW)
                        .addComponent(labelSE))
        );
        contentPane.setLayout(layout);
        setContentPane(contentPane);
        pack();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                LabelFrame frame = new LabelFrame();
                frame.setVisible(true);
            }
        });
    }

}
durron597
  • 31,968
  • 17
  • 99
  • 158
  • Is there a way to remove the initial gaps? I've only managed to remove the vertical gaps. – kir Aug 14 '13 at 01:27
  • @user2280704 What gaps are you talking about? – durron597 Aug 14 '13 at 01:28
  • If you want to remove the starting gaps between the icons, change **both** `20,50` to `0,0` – durron597 Aug 14 '13 at 01:29
  • That's what I did, however I still see a horizontal gap between NW SW and NE SE... or I'm just compiling it wrong. – kir Aug 14 '13 at 01:31
  • @user2280704 That happens to me as well in my test program, but it's because the minimize/maximize/close icons in windows 7 are too large for `pack()` to shrink it properly. In fact, I can't shrink it enough because of those Icons. – durron597 Aug 14 '13 at 01:33
  • @user2280704 You may want to try removing those buttons by wrapping the `JFrame` in a `JDialog`. Have a look at this: http://stackoverflow.com/questions/2665355/how-do-i-remove-the-maximize-and-minimize-buttons-from-a-jframe – durron597 Aug 14 '13 at 01:34
  • Oh I see I completely overlooked that fact. Works completely fine then! – kir Aug 14 '13 at 01:35
2

I've tried using a layout manager..

Layout managers are wonderful at what they do, but are perhaps the wrong tool for this job. Consider using a custom border instead. Here is an example.

Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433