Removendo espaço ao redor dos botões no GridBagLayout

Eu tenho essa fonte irritante escrita para demonstrar um layout para uma tela de jogo mencionada emoutra pergunta. Ele coloca botões (ou etiquetas, escolhidos na inicialização) em umGridBagLayout.

Se você optar por não usar botões quando solicitado (antes que a GUI apareça), toda a GUI será agradável e compacta, sem falhas. Mas se você optar por usar os botões, será (se a sua configuração for como a minha) parecer algo como isto ..

Observe as linhas horizontais vermelhas. Essa é a cor BG do painel que aparece. Essas linhas não são vistas quando a GUI usa rótulos. Estique um pouco a GUI para ver que ela nem está colocando uma linha vermelha após cada linha (há nove linhas) - embora cada linha use botões (os mesmos componentes).

Como remover o espaço vertical extra ao usar botões?

Eu acho que deve ser algo que eu esqueço de fazer ao configurar os botões ou os pesos das linhas, mas não consigo descobrir o que!

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("http://i.stack.imgur.com/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);
    }
}

questionAnswers(1)

yourAnswerToTheQuestion