Removing space around buttons in GridBagLayout
Asked Answered
A

1

7

I have this vexing source written to demonstrate a layout for a game screen mentioned on another question. It puts buttons (or labels, choosable at start-up) into a GridBagLayout.

If you choose to not use buttons when prompted (before the GUI appears) the entire GUI is nice and compact with no gaps. But if you choose to use buttons it will (if your set up is like mine) look something like this..

enter image description here

Note the red horizontal lines. That is the BG color of the panel showing through. Those lines are not seen when the GUI uses labels. Stretch the GUI a bit to see that it is not even putting a red line after every row (there are nine rows) - though each row uses buttons (the same components).

How to remove the extra vertical space when using buttons?

I figure it must be something I'm forgetting to do when configuring the buttons or the row weights, but I cannot figure out what!

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

import java.net.URL;
import javax.imageio.ImageIO;

public class SoccerField {

    private JPanel ui = null;
    int[] x = {0, 35, 70, 107, 142, 177, 212, 247, 282, 315};
    int[] y = {0, 45, 85, 140, 180, 225, 265, 280, 320, 345};
    boolean buttons;

    SoccerField() {
        initUI();
    }

    public void initUI() {
        int result = JOptionPane.showConfirmDialog(ui, "Use buttons?");
        buttons = result == JOptionPane.OK_OPTION;
        if (ui != null) {
            return;
        }

        ui = new JPanel(new GridBagLayout());
        ui.setBackground(Color.RED);

        try {
            URL url = new URL("https://i.sstatic.net/9E5ky.jpg");
            BufferedImage img = ImageIO.read(url);
            BufferedImage field = img.getSubimage(100, 350, 315, 345);

            BufferedImage[] bi = subSampleImageColumns(field);
            BufferedImage[][] fieldParts = new BufferedImage[bi.length][];
            for (int ii=0; ii<bi.length; ii++) {
                fieldParts[ii] = subSampleImageRows(bi[ii]);
            }
            for (int ii=0; ii<fieldParts[0].length; ii++) {
                for (int jj=0; jj<fieldParts.length; jj++) {
                    addImageToPanel(ui, fieldParts[ii][jj], ii, jj);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void addImageToPanel(JPanel panel, BufferedImage img, int row, int col) {
        Insets insets = new Insets(0,0,0,0);
        GridBagConstraints gbc = new GridBagConstraints(
                row, col, 
                1, 1, 
                .5, .5, 
                GridBagConstraints.CENTER, 
                GridBagConstraints.BOTH, 
                insets, 0, 0);
        ImageIcon ii = new ImageIcon(img);
        JButton b = new JButton(ii);
        b.setBorder(null);
        b.setBorderPainted(false);
        b.setContentAreaFilled(false);
        Component c = buttons ? b : new JLabel(ii);
        panel.add(c, gbc);
    }

    private BufferedImage[] subSampleImageColumns(BufferedImage img) {
        System.out.println("Image Size: " + img.getWidth() + "," + img.getHeight());
        BufferedImage[] imageRows = new BufferedImage[x.length - 1];
        for (int ii = 0; ii < x.length - 1; ii++) {
            BufferedImage bi = img.getSubimage(
                    x[ii], 0, x[ii + 1] - x[ii], img.getHeight());
            imageRows[ii] = bi;
        }

        return imageRows;
    }

    private BufferedImage[] subSampleImageRows(BufferedImage img) {
        BufferedImage[] imageRows = new BufferedImage[y.length - 1];
        for (int ii = 0; ii < y.length - 1; ii++) {
            BufferedImage bi = img.getSubimage(
                    0, y[ii], img.getWidth(), y[ii + 1] - y[ii]);
            imageRows[ii] = bi;
        }

        return imageRows;
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception useDefault) {
                }
                SoccerField o = new SoccerField();

                JFrame f = new JFrame(o.getClass().getSimpleName());
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setLocationByPlatform(true);

                f.setContentPane(o.getUI());
                f.pack();
                //f.setMinimumSize(f.getSize());

                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
Antipersonnel answered 12/9, 2015 at 16:12 Comment(4)
Stupid question: have you tried specifying an EmptyBorder (with insets of 0 for all 4 values) instead of null when setting your button's border? Does it change anything?Forbis
@Forbis No it's not a stupid question and yes I sure have. Same effect. The only reason I didn't offer a variant that does that is laziness at adding the functionality (as opposed to just changing a line of code and recompiling) and then selecting one or the other every time it runs. ;)Antipersonnel
@Forbis As an aside, that code is entirely self contained, so it should be pretty easy for people to run. It pulls the image direct from imgur at run-time.Antipersonnel
Yeah I just tried your code. It seems the frame does not have the same size after the call to pack () whether you are running with buttons or labels. Still trying to see if I can find something quickly.Forbis
S
6

Noticed that the preferred height of the buttons doesn't seem to be calculated correctly for the buttons (in some cases).

In the cases where the height of the label is 40, the height of the button was 41.

Its like the button will always resize to an odd number?

I changed the code:

//int[] y = {0, 45, 85, 140, 180, 225, 265, 280, 320, 345};
int[] y = {0, 45, 86, 139, 180, 225, 266, 279, 320, 345};

and it seems to work.

Ah, just found the reason. You also need:

b.setFocusPainted(false);
Skein answered 12/9, 2015 at 16:33 Comment(1)
"..and it seems to work. .. Ah, just found the reason" Yes, that's it. Brilliant!Antipersonnel

© 2022 - 2024 — McMap. All rights reserved.