I’ve recently started to work with the java GUI -most properly Swing.
Now I got this problem I just can’t get around.
I want to dispose a game board that extends JPanel and implements ActionListener (something) like this:
+----------------+
| Panel1 | Board |
|________| |
| Panel2 | |
| | |
+----------------+
But I’m getting this:
+----------------+
| Panel1 | Board |
|________|_______|
| Panel2 | EMPTY |
| | |
+----------------+
I started by trying to do this using the GridLayout for the main pane with BoxLayouted panels inside but that didn’t work. Then I found GroupLayout, wich lead me to the above case and made me lost control/focus of my listener inside the board class.
[EDIT] I also tried to change the minimun and prefered sizes of board, didn’t worked either.
Can anyone tell me why this is happening?
Resuming:
- Why is the group layout doing this to the Board panel? Anyway I can fix it?
- Since inside the Board class I do setFocusable(true); why can’t it get actions/events after being inside the group layout?(Works fine without it)
Here’s the code:
Game class
...
public ConstructorOfTheClassThatExtendsJFrame() {
statusbar = new JLabel(" 0");
panel = new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.black));
this.getContentPane().add(panel);
Board board = new Board(this);
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
//Specify automatic gap insertion:
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
//PANEL 1
col1 = new JPanel();
col1.setBorder(BorderFactory.createLineBorder(Color.black));
//PANEL 3
col3 = new JPanel();
col3.add(statusbar);
layout.setHorizontalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(col1)
.addComponent(col3))
.addComponent(board)
);
layout.setVerticalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(col1)
.addComponent(board))
.addComponent(col3)
);
setSize(400, 400);
setResizable(false);
setTitle("GameOn");
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
and my Board class (from ZetCode)
public Board(Game parent) {
setFocusable(true);
curPiece = new Shape();
timer = new Timer(400, this);
timer.start();
statusbar = parent.getStatusBar();
board = new Tetrominoes[BoardWidth * BoardHeight];
addKeyListener(new TAdapter());
clearBoard();
}
...
class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (!isStarted || curPiece.getShape() == Tetrominoes.NoShape) {
return;
}
int keycode = e.getKeyCode();
if (keycode == 'p' || keycode == 'P') {
pause();
return;
}
if (isPaused)
return;
switch (keycode) {
case KeyEvent.VK_LEFT:
tryMove(curPiece, curX - 1, curY);
break;
case KeyEvent.VK_RIGHT:
tryMove(curPiece, curX + 1, curY);
break;
case KeyEvent.VK_DOWN:
//tryMove(curPiece, curX, curY - 1);
oneLineDown();
break;
case KeyEvent.VK_UP:
tryMove(curPiece.rotateRight(), curX, curY);
break;
case KeyEvent.VK_SPACE:
dropDown();
break;
case 'd':
oneLineDown();
break;
case 'D':
oneLineDown();
break;
case KeyEvent.VK_SHIFT:
newPiece();
break;
}
}
[EDIT] After some advice, here’s a sscce version of the code where the key events work but the alignment is still wrong:
The game class(this case is hello world but still)
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Color;
public class HelloWorldSwing{
private static void createAndShowGUI(){
//Create frame
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.black));
frame.getContentPane().add(panel);
//Create the new group layout
GroupLayout layout = new GroupLayout(panel);
panel.setLayout(layout);
//We specify automatic gap insertion:
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
//PANEL 1
JPanel col1 = new JPanel();
col1.setBorder(BorderFactory.createLineBorder(Color.black));
//PANEL 2
JLabel label2 = new JLabel("Col2");
Board board = new Board(label2, new BorderLayout());
//PANEL 3
JPanel col3 = new JPanel();
JLabel label = new JLabel("Col1");
JLabel label3 = new JLabel("Col3");
col1.add(label);
board.add(label2,BorderLayout.PAGE_END);
col3.add(label3);
layout.setHorizontalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(col1)
.addComponent(col3))
.addComponent(board)
);
layout.setVerticalGroup(
layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(col1)
.addComponent(board))
.addComponent(col3)
);
frame.setSize(300, 400);
frame.setVisible(true);
}
public static void main(String[] args){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
And the board class:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.BorderLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class Board extends JPanel implements ActionListener {
JLabel blabel;
public Board(JLabel label, BorderLayout b) {
super(b);
setFocusable(true);
blabel = label;
addKeyListener(new TAdapter());
}
public void actionPerformed(ActionEvent e) {
}
class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();
switch (keycode) {
case KeyEvent.VK_LEFT:
blabel.setText("Left");
break;
case KeyEvent.VK_RIGHT:
blabel.setText("Right");
break;
case KeyEvent.VK_DOWN:
blabel.setText("Down");
break;
}
}
}
}
Thanks for your time!
I see one thing in your code that could be a problem and that may be fixed without too much difficulty: you’re using KeyListeners. This should in general be avoided in Swing GUI’s and instead you should try to use Key Bindings which are more flexible and which do not require that the bound component have focus.
Regarding your GroupLayout sizing issue, I have to admit to being very weak on use of GroupLayout, and in fact I try to avoid its use assiduously. Other layouts to consider include GridBagLayout or the MigLayout.
Edit:
However, I have now read the GroupLayout tutorial, including section labeled “To force a component to be resizable (allow shrinking and growing):”. It appears that you must add some parameters when you add your component to the layout which in my code example looks like:
For instance, here’s my code showing components laid out as desired, and also showing use of KeyBindings and a PropertyChangeListener. Notice that by using Key Bindings, focus is no longer as big of an issue as I don’t have to set the JPanel to be focusable nor to give it the focus:
Which will look like so:

I’m a big fan of using PropertyChangeListeners for this sort of thing since it allows for easy decoupling of your code. Now the Board2 class doesn’t have to worry about how other classes react to any changes in its direction. All it must do is broadcast this change to any classes that happening to be listening to it, and they each respond as they see fit.