0

I am trying to make a keyboard GUI with Java Swing, not JavaFX, so I am using a GridBagLayout with GridBagConstraint.

The problem is that the keys that I want to span three columns, such as the TAB key, end up pushing the keys in the row above it. I am being careful to have a consistent 30 columns in the entire layout and the cell positions that I'm adding JButtons to look correct to me.

I am using 30 columns so I have enough precision to span three columns and end the button halfway under the key above it. so, each normal key spans two columns, TAB spans 3, backspace spans 4, etc.

private final int KEYBOARD_NUM_ROWS = 5;
private final int KEYBOARD_NUM_COLS = 30;

Keyboard() {
    setLayout(new GridBagLayout());
    GridBagConstraints gc = new GridBagConstraints();

    // Constraint Setup
    gc.fill = GridBagConstraints.VERTICAL; // changing to BOTH just stretches the buttons
    gc.anchor = GridBagConstraints.WEST;
    gc.weightx = 0;
    gc.weighty = 0;

    // Button Size Types
    final Dimension twoSpan = new Dimension(45, 40);
    final Dimension threeSpan = new Dimension(65, 40);
    final Dimension fourSpan = new Dimension(85, 40);

    // Keyboard First Row
    int colNum = 0;
    int rowNum = 0;

    while (colNum < KEYBOARD_NUM_COLS) {
        JButton key = new JButton();
        key.setFocusPainted(false);

        if (colNum == 26) {
            key.setPreferredSize(fourSpan);
            gc.gridwidth = 4;
        } else {
            key.setPreferredSize(twoSpan);
            gc.gridwidth = 2;
        }

        gc.gridy = rowNum;
        gc.gridx = colNum;

        colNum += gc.gridwidth;
        add(key, gc);
    }

    // Keyboard Second Row
    colNum = 0;
    rowNum = 1;

    while (colNum < KEYBOARD_NUM_COLS) {
        JButton key = new JButton();
        key.setFocusPainted(false);

        if (colNum == 0) {
            key.setPreferredSize(threeSpan);
            gc.gridwidth = 3;
        } else if (colNum == 27) {
            key.setPreferredSize(threeSpan);
            gc.gridwidth = 3;
        } else {
            key.setPreferredSize(twoSpan);
            gc.gridwidth = 2;
        }

        gc.gridy = rowNum;
        gc.gridx = colNum;

        colNum += gc.gridwidth;
        add(key, gc);
    }

The two first rows of the keyboard GUI

The first row seems to be pushed by the button that spans three rows.

Anyone know how to fix this?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Chris
  • 40
  • 6
  • *I am being careful to have a consistent 30 columns in the entire layout* - you can't just make each row occupy 30 columns. You actually need to have a component in each of the 30 columns, or tell GridBagLayout what the size of a column should be if no component is in each column. See: https://stackoverflow.com/questions/27371956/why-does-this-gridbaglayout-not-appear-as-planned/57463596#57463596 for a working example on how to do this. – camickr Nov 22 '19 at 20:14
  • Also don't attempt to set the preferred size of a component that spans multiple columns. The size of the component will be determined by the width of each of the columns you are trying to span. – camickr Nov 22 '19 at 20:39
  • The purpose of GridBagLayout is a grid. Unless you provide something to fit each cell of said grid, or use gridwidth/height, you won't get a result. For all that matters, you can also write you own layout or position component manually (using setLayout(null) and setBounds on each button). **Edit:** you can also try using one panel per row, and a FlowLayout per cell. – NoDataFound Nov 22 '19 at 20:41
  • @camickr Ok that post really helped, I managed to achieve the button layout I wanted. Thanks! – Chris Nov 22 '19 at 21:46
  • @NoDataFound Yes I was on the verge of using a unique layout per row and then stacking them together but I really wanted to stick with just one GridBagLayout. – Chris Nov 22 '19 at 21:49

0 Answers0