Search code examples
javaswingjpanellayout-managergridbaglayout

Custom JPanel causing unusual GridBagConstraint layout behavoiur


I'm developing a simple image editing program to adjust brightness/contrast. My custom JPanel is simply used to display the loaded image, but it is causing my sliders and labels on the next column to display incorrectly.

import java.awt.*;
import javax.swing.*;

public class IMView extends JFrame  implements Observer {

JButton selectIMGFolder = new JButton("Select Folder");
ImagePanel originalImage;
//Labels and sliders to control image
JLabel brightnessLabel = new JLabel("Brightness");
JSlider brightness = new JSlider(-255,255,0);
JLabel contrastLabel = new JLabel("Contrast");
JSlider contrastSlider = new JSlider(-255,255,0);

JLabel random = new JLabel("Random Test Label");

public IMView (){
    super("Image manipulation");

    JPanel mainJPanel = new JPanel();
    mainJPanel.setLayout(new GridBagLayout());

    GridBagConstraints gc = new GridBagConstraints();

    originalImage = new ImagePanel();
    //first column

    gc.anchor = GridBagConstraints.LINE_START;
    gc.weightx = 0.5;
    gc.weighty = 0.5;

    gc.gridx = 0;
    gc.gridy = 0;
    mainJPanel.add(selectIMGFolder, gc);

    gc.gridx = 0;
    gc.gridy = 1;

    mainJPanel.add(originalImage, gc);

    gc.gridx = 0;
    gc.gridy = 2;
    mainJPanel.add(random, gc);

    //second column
    //brightness

    gc.gridx = 1;
    gc.gridy = 0;

    mainJPanel.add(brightnessLabel, gc);

    gc.gridx = 1;
    gc.gridy = 1;
    mainJPanel.add(brightness, gc);

    gc.gridx = 1;
    gc.gridy = 2;
    mainJPanel.add(contrastLabel, gc);

    gc.weighty = 10;
    gc.anchor = GridBagConstraints.FIRST_LINE_START;
    gc.gridx = 1;
    gc.gridy = 3;       
    mainJPanel.add(contrastSlider, gc);

    this.add(mainJPanel);
    this.setVisible(true);
    this.setPreferredSize(new Dimension(800, 600));
    this.pack();
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

//other code
}

Heres my simple custom panel:

public class ImagePanel extends JPanel {

Image image;

public ImagePanel(){
    this.setPreferredSize(new Dimension(400,300));

}   

//set image file some where

@Override
public void paintComponent(Graphics g){
    super.paintComponents(g);
    g.setColor(Color.red);
    g.fillRect(0, 0, 400,300);
    if(image != null){
         g.drawImage(image, 0,0, this);
    }

}

}

The below is the result of the code (where red square represents an image), I essentially want the sliders and labels on the right hand side to be packed together. If I don't add the custom panel to mainJPanel it seems to look how I want.

enter image description here


Solution

  • GridBagLayout is complex enough without laying out everything within a single container. Break up your form into areas of responsibility and use separate containers.

    enter image description here

    public class BadLayout08 {
    
        public static void main(String[] args) {
            new BadLayout08();
        }
    
        public BadLayout08() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new IMView();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class IMView extends JFrame {
    
            JButton selectIMGFolder = new JButton("Select Folder");
            JPanel originalImage;
    //Labels and sliders to control image
            JLabel brightnessLabel = new JLabel("Brightness");
            JSlider brightness = new JSlider(-255, 255, 0);
            JLabel contrastLabel = new JLabel("Contrast");
            JSlider contrastSlider = new JSlider(-255, 255, 0);
            JLabel random = new JLabel("Random Test Label");
    
            public IMView() {
                super("Image manipulation");
    
                JPanel mainJPanel = new JPanel();
                mainJPanel.setLayout(new GridBagLayout());
    
                GridBagConstraints gc = new GridBagConstraints();
    
                originalImage = new JPanel();
                originalImage.setPreferredSize(new Dimension(400, 300));
                originalImage.setBackground(Color.RED);
                //first column
    
                gc.anchor = GridBagConstraints.LINE_START;
    
                gc.gridx = 0;
                gc.gridy = 0;
                mainJPanel.add(selectIMGFolder, gc);
    
                gc = new GridBagConstraints();
                gc.anchor = GridBagConstraints.LINE_START;
                gc.gridx = 0;
                gc.gridy = 1;
                mainJPanel.add(originalImage, gc);
    
                gc = new GridBagConstraints();
                gc.gridx = 0;
                gc.gridy = 2;
                mainJPanel.add(random, gc);
    
                //second column
                //brightness
    
                JPanel sidePane = new JPanel(new GridBagLayout());
                gc = new GridBagConstraints();
    
                gc.gridx = 1;
                gc.gridy = 0;
    
                sidePane.add(brightnessLabel, gc);
    
                gc.gridx = 1;
                gc.gridy = 1;
                sidePane.add(brightness, gc);
    
                gc.gridx = 1;
                gc.gridy = 2;
                sidePane.add(contrastLabel, gc);
    
                gc.weighty = 10;
                gc.anchor = GridBagConstraints.FIRST_LINE_START;
                gc.gridx = 1;
                gc.gridy = 3;
                sidePane.add(contrastSlider, gc);
    
                gc = new GridBagConstraints();
                gc.gridx = 1;
                gc.gridy = 1;
                gc.gridheight = GridBagConstraints.REMAINDER;
                gc.anchor = GridBagConstraints.NORTH;
                mainJPanel.add(sidePane, gc);
    
                this.add(mainJPanel);
                this.setVisible(true);
                this.setPreferredSize(new Dimension(800, 600));
                this.pack();
                this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
    //other code
        }
    }