0

I'm trying to set up a puzzle editor/solver with an interactable canvas on the left, selectable tools on the top right, and a big "Solve" button plus some replay buttons in the bottom right. I'm using a couple of GridBagLayouts (one for the main layout and one for the buttons) and in both places it looks like neither the sizes nor the margins are getting calculated correctly.

Here's a picture of what it's displaying:

https://i.stack.imgur.com/tu6RC.png

What I'd like is a 10-pixel margin around the contents, and 10-pixel margins within each of the right-hand sections, but it's giving me a 15-pixel margin on top and god-knows-what on the bottom and sides. The sub-JPanels are also not being sized correctly, as you can see the content is too large for the window. I'm using a simple box layout for the radio buttons and nothing seems to be wrong with the sizing or margins there. I'm using the expected pixel values as the grid weights because in my mind, that should size them correctly. Any ideas why the margins and sizes are completely broken?

Relevant code attached. EditorToolsGroup is a sub-component that creates the radio buttons. and SolveButtons is a sub-component that creates the solve/replay buttons. I can include the code for SolveButtons if requested, but there's really not anything different going on there.

public class Editor implements ActionListener {
    private static final String WINDOW_TITLE = "Golem Puzzle Editor";

    private static final int WINDOW_WIDTH = 1500;
    private static final int WINDOW_HEIGHT = 800;
    private static final int WINDOW_MARGIN = 10;
    private static final int CONTROLS_WIDTH = 180;
    private static final int SOLVE_BUTTONS_HEIGHT = 100;
    private static final int RADIO_BUTTONS_HEIGHT = WINDOW_HEIGHT - SOLVE_BUTTONS_HEIGHT - 2*WINDOW_MARGIN;
    private static final int CANVAS_WIDTH = WINDOW_WIDTH - CONTROLS_WIDTH - 2*WINDOW_MARGIN;
    private static final int CANVAS_HEIGHT = WINDOW_HEIGHT - 2*WINDOW_MARGIN;

    private JFrame window;
    private EditorCanvas canvas;

    public Editor() {
        this.window = new JFrame(WINDOW_TITLE);
        this.window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);

        JPanel mainPanel = new JPanel();
        Border margin = new EmptyBorder( WINDOW_MARGIN, WINDOW_MARGIN, WINDOW_MARGIN, WINDOW_MARGIN);
        mainPanel.setBorder(margin);
        this.window.add(mainPanel);
        JPanel subPanel = new JPanel();
        subPanel.setLayout(new GridBagLayout());
        mainPanel.add(subPanel);

        this.setupCanvas(subPanel);
        this.createRadioButtons(subPanel);
        this.createSolveButtons(subPanel);

        this.window.setVisible(true);
    }

    private void setupCanvas(JPanel parent) {
        this.canvas = new EditorCanvas();
        this.canvas.setBackground(Color.RED);
        this.canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));

        GridBagConstraints canvasConstraints = new GridBagConstraints();
        canvasConstraints.fill = GridBagConstraints.BOTH;
        canvasConstraints.gridwidth = 1;
        canvasConstraints.gridheight = 2;
        canvasConstraints.gridx = 0;
        canvasConstraints.gridy = 0;
        canvasConstraints.weightx = CANVAS_WIDTH;
        canvasConstraints.weighty = CANVAS_HEIGHT;
        parent.add(this.canvas, canvasConstraints);
    }

    private void createRadioButtons(JPanel parent) {
        EditorToolsGroup editorToolsGroup = new EditorToolsGroup(this);
        JPanel editorToolsGroupPanel = editorToolsGroup.getPanel();
        editorToolsGroupPanel.setBackground(Color.GREEN);
        editorToolsGroupPanel.setPreferredSize(new Dimension(CONTROLS_WIDTH, RADIO_BUTTONS_HEIGHT));

        GridBagConstraints toolsGroupConstraints = new GridBagConstraints();
        toolsGroupConstraints.fill = GridBagConstraints.BOTH;
        toolsGroupConstraints.gridwidth = 1;
        toolsGroupConstraints.gridheight = 1;
        toolsGroupConstraints.gridx = 1;
        toolsGroupConstraints.gridy = 0;
        toolsGroupConstraints.weightx = CONTROLS_WIDTH;
        toolsGroupConstraints.weighty = RADIO_BUTTONS_HEIGHT;
        parent.add(editorToolsGroupPanel, toolsGroupConstraints);
    }

    private void createSolveButtons(JPanel parent) {
        SolveButtons solveButtons = new SolveButtons(this);
        JPanel solveButtonsPanel = solveButtons.getPanel();
        solveButtonsPanel.setBackground(Color.BLUE);
        solveButtonsPanel.setPreferredSize(new Dimension(CONTROLS_WIDTH, SOLVE_BUTTONS_HEIGHT));

        GridBagConstraints buttonConstraints = new GridBagConstraints();
        buttonConstraints.fill = GridBagConstraints.BOTH;
        buttonConstraints.gridwidth = 1;
        buttonConstraints.gridheight = 1;
        buttonConstraints.gridx = 1;
        buttonConstraints.gridy = 1;
        buttonConstraints.weightx = CONTROLS_WIDTH;
        buttonConstraints.weighty = SOLVE_BUTTONS_HEIGHT;
        parent.add(solveButtonsPanel, buttonConstraints);
    }

    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        // TODO
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
dscherzi
  • 1
  • 1
  • 2
    Don't hard code sizes and use setPreferredSize(). A Swing component should be able to determine its own preferred size. You then logically group components on a panel using an appropriate layout manager. You then determine appropriate sizing behaviour for each panel. A picture of what is displaying doesn't help. What we need is an ascii drawing to show "what your want". – camickr Jun 20 '21 at 02:33
  • I see you using the BorderLayout of the JFrame. Then your "solver panel" to the CENTER. Then you create another panel with a BorderLayout that you add to the LINE_END. In this second panel you then add the "tool bar panel" to the PAGE_START and the "button panel" to the PAGE_END. You can use `frame.setExtendedState(JFrame.MAXIMIZED_BOTH);` to maximize the frame with it it displayed. – camickr Jun 20 '21 at 02:33
  • I'm now realizing that I can do everything I want with appropriately nested box layouts, but I'm still interested in why using GridBagLayout completely doesn't work here. – dscherzi Jun 20 '21 at 02:51
  • Interesting fact: if I remove all the calls to setPreferredSize(), the radio button area, the solve button area, and the margins all render correctly, but the canvas doesn't naturally calculate its size correctly and ends up embarrassingly small. So if I can get the canvas to size properly I think we can call this solved. – dscherzi Jun 20 '21 at 03:00
  • I already stated I would guess because of all your hard coded values. If is the job of the layout manager to set the size of components. I would suggest only the canvas needs to grow/shrink as the frame size changes, so only it should have weightx/y constraints. For the other components you can use the "anchor" constraint to position the panel at the top or bottom. Again without a drawing of some kind to show us want you want I can't really say. – camickr Jun 20 '21 at 03:01
  • 2
    *but the canvas doesn't naturally calculate its size correctly* When you create a custom canvas you class should implement `getPreferredSize()` to give the component a default size. – camickr Jun 20 '21 at 03:03

0 Answers0