Search code examples
javaswinggridbaglayoutjprogressbarpreferredsize

JProgressBar Gets Squeezed/ Resizes Improperly


I'm using a JProgressBar on my Swing gui:

When I minimize the window while it's updating with progressBar.setValue() it will squeeze like this:

Note that resizing or similar doesn't fix it.

Why does it happen and how to prevent it? What causes it? I want the progressbar to stay the same size like in the first image.

I'm using the GridBagLayout.

Code to reproduce:

import javax.swing.JFrame;
import javax.swing.SwingWorker;

import java.awt.Dimension;
import java.awt.GridBagLayout;

import javax.swing.JProgressBar;

import java.awt.GridBagConstraints;

import javax.swing.JButton;

import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;

@SuppressWarnings("serial")
public class ProgressBarSqueezeFixedExample extends JFrame
{
    public ProgressBarSqueezeFixedExample()
    {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(500, 500);
        GridBagLayout gridBagLayout = new GridBagLayout();
        gridBagLayout.columnWidths = new int[] { 0, 0, 0 };
        gridBagLayout.rowHeights = new int[] { 0, 0, 0, 0, 0 };
        gridBagLayout.columnWeights = new double[] { 1.0, 0.0, Double.MIN_VALUE };
        gridBagLayout.rowWeights = new double[] { 0.0, 0.0, 0.0, 1.0,
                Double.MIN_VALUE };
        getContentPane().setLayout(gridBagLayout);

        JProgressBar progressBar = new JProgressBar();

        JTextArea textArea = new JTextArea();

        JButton btnRun = new JButton("Run");
        setPreferredSize(new Dimension(200, 200));

        btnRun.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent arg0)
            {
                SwingWorker<String, String> worker = new SwingWorker<String, String>()
                {
                    @Override
                    protected String doInBackground() throws Exception
                    {
                        for (int i = 0; i < 10001; i++)
                        {
                            try
                            {
                                Thread.sleep(1);
                            } catch (InterruptedException e)
                            {
                                e.printStackTrace();
                            }

                            progressBar.setValue(i);
                            progressBar.setString(i + " %");

                            textArea.append(i + System.lineSeparator());
                        }

                        return null;
                    }
                };

                worker.execute();
            }
        });
        GridBagConstraints gbc_btnRun = new GridBagConstraints();
        gbc_btnRun.insets = new Insets(0, 0, 5, 5);
        gbc_btnRun.gridx = 0;
        gbc_btnRun.gridy = 0;
        getContentPane().add(btnRun, gbc_btnRun);

        JLabel lblProgress = new JLabel("Progress");
        GridBagConstraints gbc_lblProgress = new GridBagConstraints();
        gbc_lblProgress.insets = new Insets(0, 0, 5, 5);
        gbc_lblProgress.gridx = 0;
        gbc_lblProgress.gridy = 1;
        getContentPane().add(lblProgress, gbc_lblProgress);

        progressBar.setMaximum(10000);
        progressBar.setStringPainted(true);
        progressBar.setMinimumSize(progressBar.getPreferredSize()); // Fixes squeezing issues

        GridBagConstraints gbc_progressBar = new GridBagConstraints();
        gbc_progressBar.insets = new Insets(0, 0, 5, 5);
        gbc_progressBar.gridx = 0;
        gbc_progressBar.gridy = 2;
        getContentPane().add(progressBar, gbc_progressBar);

        JScrollPane scrollPane = new JScrollPane();
        GridBagConstraints gbc_scrollPane = new GridBagConstraints();
        gbc_progressBar.fill=GridBagConstraints.HORIZONTAL; // Alternate fix
        gbc_scrollPane.gridwidth = 2;
        gbc_scrollPane.fill = GridBagConstraints.BOTH;
        gbc_scrollPane.gridx = 0;
        gbc_scrollPane.gridy = 3;
        getContentPane().add(scrollPane, gbc_scrollPane);

        scrollPane.setViewportView(textArea);
        pack();

        setVisible(true);
    }

    public static void main(String[] args)
    {
        new ProgressBarSqueezeFixedExample();
    }
}

The resizing of the gui and squeezing the progressbar has to to with the textArea append() how it seems.


Solution

  • Use GridBagConstraints#fill property that is used when the component's display area is larger than the component's requested size. It determines whether to resize the component.

    gbc_progressBar.fill=GridBagConstraints.HORIZONTAL;
    

    Note: There is no need to create multiple instance of GridBagConstraints. you can achieve same thing using single object as well.

    Read more about How to Use GridBagLayout and have a look at the example.