Вопрос

I have some strange behaviour with MigLayout. I have an SSCCE that reflects my problem. Basically, there is a gap between the top two panels (the gap belongs to the left cell). Everything else is just as I want it. The gap only occurs when the JFrame is large resized and large enough.

SSCCE

The left panel (named Measurement) should have a fixed width, while the middle panel (named Config) is pushx, growx and should therefore fill in all the space left by the other two components on that row. But the left panel cell seems to steal the remaining space.

How can I remove that space (so that the config panel directly touches the measurement panel and the measurement panel is exactly 500 px wide)?

I am using MigLayout 4.0.

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

import net.miginfocom.swing.MigLayout;

public class Main {
    private static JButton minimizeButton;
    private static JPanel configPanel, plotPanel, measPanel;

    public static void main(final String[] args) {
        final JFrame frame = new JFrame("test");

        frame.setLayout(new MigLayout("insets 10, hidemode 3, debug", "", ""));

        frame.add(getMeasPanel(), "w 500!");
        frame.add(getConfigPanel(), "left, grow, pushx");
        frame.add(getMinimizeButton(), "right, top, wrap");
        frame.add(getPlotPanel(), "spanx 3, grow, push, wrap");

        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    private static JPanel getConfigPanel() {
        if (configPanel == null) {
            configPanel = new JPanel(new MigLayout("insets 10"));
            configPanel.add(new JLabel("test123"), "spanx 2, wrap");
            configPanel.add(new JLabel("test123"), "h 40!");
            configPanel.add(new JLabel("test123"), "right, wrap");
            configPanel.setBorder(BorderFactory.createTitledBorder(null,
                    "Plot", TitledBorder.LEFT, TitledBorder.TOP, new Font(
                            "null", Font.BOLD, 12), Color.BLUE));
        }
        return configPanel;
    }

    private static JButton getMinimizeButton() {
        if (minimizeButton == null) {
            minimizeButton = new JButton("_");
            minimizeButton.setFocusPainted(false);
            minimizeButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    toggleConfigMinimize();
                }
            });
        }
        return minimizeButton;
    }

    private static JPanel getPlotPanel() {
        if (plotPanel == null) {
            plotPanel = new JPanel();
            plotPanel.setBorder(BorderFactory.createTitledBorder(null,
                    "Plot Config", TitledBorder.LEFT, TitledBorder.TOP,
                    new Font("null", Font.BOLD, 12), Color.BLUE));
        }
        return plotPanel;
    }

    private static JPanel getMeasPanel() {
        if (measPanel == null) {
            measPanel = new JPanel(new MigLayout("insets 10"));
            measPanel.add(new JLabel("test123"), "spanx 2, wrap");
            measPanel.add(new JLabel("test123"), "h 40!");
            measPanel.add(new JLabel("test123"), "right, wrap");
            measPanel.add(new JLabel("test123"), "spanx 2, wrap");
            measPanel.add(new JLabel("test123"), "spanx 2, wrap");
            measPanel.setBorder(BorderFactory.createTitledBorder(null,
                    "Measurement", TitledBorder.LEFT, TitledBorder.TOP,
                    new Font("null", Font.BOLD, 12), Color.BLUE));
        }
        return measPanel;
    }

    private static boolean showConfig = true;

    protected static void toggleConfigMinimize() {
        showConfig = !showConfig;
        getMeasPanel().setVisible(showConfig);
        getConfigPanel().setVisible(showConfig);
    }
}
Это было полезно?

Решение

A solution is to define the growing behaviour of the config-column in the column constraints:

frame.setLayout(new MigLayout("insets 10, hidemode 3, debug",
        "[][fill, grow][]", ""));
frame.add(getMeasPanel(), "w 500!");
frame.add(getConfigPanel(), "left, grow");
frame.add(getMinimizeButton(), "right, top, wrap");
frame.add(getPlotPanel(), "spanx 3, grow, wrap, push");

There are some quirks (read: behaviour I personally don't fully understand :-) with push cell contraints, so I tend to evade them where possible. Also, my preference would be to define a wrap 3 in the layout constraints.

Update:

Just remembered one of the quirks: the push (actually the implied pushx) in the spanning plot row is the real culprit - its excess space goes into its first column. Thinking about it, that behaviour is not sooo not unreasonable, after all cell contstraints are about ... cells, they don't much care about other cells.

So another solution is to make the plot pushy in y only (the x push being already handled by the config cell in the second column above it)

frame.setLayout(new MigLayout("insets 10, hidemode 3, debug",
        // cell constraints are empty in original
        "",
        ""));

// meas should have a fixed size
frame.add(getMeasPanel(), "w 500!");
// the config should get all excess space when growing
frame.add(getConfigPanel(), "left, grow, pushx");
frame.add(getMinimizeButton(), "right, top, wrap");
// remove implicit the pushx
frame.add(getPlotPanel(), "spanx 3, grow, wrap, pushy");

My preference would be the first: do as much config as high up in a hierarchy (of constraints) as possible, makes the ui code much more maintainable than having them scattered over the cells.

Другие советы

The problem is in fixed size of your measurement panel. You add plot panel in new row with attributes of span, push, grow and when you resize your frame both cells where measurement and config panel are will be resized too, but size of your measurement panel will remain fixed acording to w 500! attribute. My recomendation is to force growth of measurement and config panel and their cells.

Like this:

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import net.miginfocom.swing.MigLayout;

public class MigTest {
    JFrame frame = new JFrame();
    JPanel msmPanel = new JPanel();
    JPanel configPanel = new JPanel();
    JPanel plotPanel = new JPanel();
    JLabel lbl1 = new JLabel("Test 123");
    JLabel lbl2 = new JLabel("Test 123");

    public MigTest() {
        frame.setLayout(new MigLayout());
        msmPanel.add(lbl1);
        configPanel.add(lbl2);
        msmPanel.setBorder(BorderFactory.createTitledBorder("Measurement"));
        configPanel
                .setBorder(BorderFactory.createTitledBorder("Configuration"));
        plotPanel.setBorder(BorderFactory.createTitledBorder("Plot"));
        frame.add(msmPanel, "pushx,grow");
        frame.add(configPanel, "pushx, grow, wrap");
        frame.add(plotPanel, "span, push, grow");

        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new MigTest();
            }
        });
    }

}

And this is what you will get: enter image description here

Good luck!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top