ImageIcon extends beyond window, resizing window expands all of components instead of showing more

Viewed 47
private void setupGUI(){
    // Setup Frame
    f = new JFrame("Shape Image Generator");
    f.setBounds(500, 150, 450, 350);
    f.setLayout(new GridLayout(8,1));
    f.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent windowEvent){
           System.exit(0);
        }
    });
}

I create the frame above, then 8 panels. I create various components and add them to the panels and everything works fine. Until I created an ImageIcon and added it to a label and added that label to the 8th panel. The image used is 140x129 pixels. The problem is, only the top.... maybe 1/4 of the image is showing. If I change the frames dimensions in the code, more empty space is created between each panel, but only a slight bit more of the image is shown, so the image is still off of the screen. I'd say the window is easily adding 10 pixels of spacing for every 1 more pixel of the image it shows. If I drag the corners of the window to expand it, the same thing happens. If the window is maximized I still can only see a little over half of my now very stretched image.

Things I tried:

  1. None of my components have preferred dimensions set, but I tried setting a preferred dimension for the label then panel that contains the ImageIcon and it only added the difference between the image and preferred size in gray space above the image, pushing it further offscreen. So, I undid that.

  2. Adding the label containing the ImageIcon to a different panel which was not the 8th and last panel, in this case, the image is still cut off, but at the point that it gets cut off, the components on the panel underneath it appear (over top of the background coloring which cuts off the image).

  3. Exhaustively Googling this situation with about 30 different ways of phrasing it and not finding a solution.

(row1 - row8 are JPanels, I didn't include the coding for them)

    ImageIcon iconStart = createImageIcon("/images/ShapeClipart.png", "Shapes");
    JLabel imgLabel = new JLabel();
    row8.add(imgLabel);

    // Add image to image label
    imgLabel.setIcon(iconStart);

    // Add panels to frame
    f.add(row1);
    f.add(row2);
    f.add(row3);
    f.add(row4);
    f.add(row5);
    f.add(row6);
    f.add(row7);
    f.add(row8);

    f.setVisible(true);

Window at execution

Window when stretched

edit: adding f.pack() makes a very tall skinny window (the windows height taller than my screen) but it still looks like when I manually expand the window (empty space between panels, image partially offscreen), even if I take out f.setBounds and only use f.setLocation.

2 Answers

You are using a GridLayout. This gives all of the enclosed panels the same amount of space. In this case it is a vertical grid.

You should probably use something a bit different. I might try a BorderLayout in the JFrame and put the a panel containing the top seven panels (in a GridLayout) into the CENTER, and then put the JLabel into the SOUTH portion of the JFrame.

There are other ways to lay it out, but this is the first I could think of.

GridLayout makes each cell in the grid the same size and the size of each cell is determined by the largest Component contained in the grid.

In your code, the icon is the largest component and you also have only one column in your grid so every row has the same height as your icon.

Since you also limit the size of your JFrame by calling method setBounds(), the Swing infrastructure cuts off the icon so that all the components fit into the bounds you specified.

One alternative, but not the only one, is to use BoxLayout since it uses the preferred size of each of its contained components.

Here is a sample GUI that matches the screen capture that you posted and uses BoxLayout.

import static javax.swing.WindowConstants.EXIT_ON_CLOSE;

import java.awt.BorderLayout;
import java.awt.EventQueue;

import java.net.URL;

import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

public class Shapes23 implements Runnable {
    private JFrame  frame;

    @Override // java.lang.Runnable
    public void run() {
        showGui();
    }

    private JPanel createEighthRow() {
        JPanel eighthRow = new JPanel();
        URL url = getClass().getResource("paint-bursht.jpg");
        Icon ico = new ImageIcon(url);
        JLabel label = new JLabel(ico);
        eighthRow.add(label);
        return eighthRow;
    }

    private JPanel createFifthRow() {
        JPanel fifthRow = new JPanel();
        JTextField textField = new JTextField(20);
        fifthRow.add(textField);
        return fifthRow;
    }

    private JPanel createFirstRow() {
        JPanel firstRow = new JPanel();
        JLabel label = new JLabel("2D Shapes");
        firstRow.add(label);
        return firstRow;
    }

    private JPanel createFourthRow() {
        JPanel fourthRow = new JPanel();
        fourthRow.add(createRadioButton("Sphere"));
        fourthRow.add(createRadioButton("Cube"));
        fourthRow.add(createRadioButton("Cone"));
        fourthRow.add(createRadioButton("Cylinder"));
        fourthRow.add(createRadioButton("Torus"));
        return fourthRow;
    }

    private JPanel createMainPanel() {
        JPanel mainPanel = new JPanel();
        BoxLayout layout = new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS);
        mainPanel.setLayout(layout);
        mainPanel.add(createFirstRow());
        mainPanel.add(createSecondRow());
        mainPanel.add(createThirdRow());
        mainPanel.add(createFourthRow());
        mainPanel.add(createFifthRow());
        mainPanel.add(createSixthRow());
        mainPanel.add(createSeventhRow());
        mainPanel.add(createEighthRow());
        return mainPanel;
    }

    private JRadioButton createRadioButton(String text) {
        JRadioButton radioButton = new JRadioButton(text);
        return radioButton;
    }

    private JPanel createSecondRow() {
        JPanel secondRow = new JPanel();
        secondRow.add(createRadioButton("Circle"));
        secondRow.add(createRadioButton("Rectangle"));
        secondRow.add(createRadioButton("Square"));
        secondRow.add(createRadioButton("Triangle"));
        return secondRow;
    }

    private JPanel createSeventhRow() {
        JPanel seventhRow = new JPanel();
        JButton button = new JButton("Enter");
        seventhRow.add(button);
        return seventhRow;
    }

    private JPanel createSixthRow() {
        JPanel sixthRow = new JPanel();
        JTextField textField = new JTextField(20);
        sixthRow.add(textField);
        return sixthRow;
    }

    private JPanel createThirdRow() {
        JPanel thirdRow = new JPanel();
        JLabel label = new JLabel("3D Shapes");
        thirdRow.add(label);
        return thirdRow;
    }

    private void showGui() {
        frame = new JFrame("Shape Image Generator");
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.add(createMainPanel(), BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Shapes23());
    }
}

Here is a screen capture of how it looks. Note that I couldn't find the same icon as in your screen capture so I just used a different one.

BoxLayout GUI Example

Related