I am writing a small game, using Swing
for GUI
and I ran into a problem. I'm posting a screenshot, so that you can get a better grasp of the situation.
At first I only had the board for which I used a GridLayout
.
However, I needed to add a panel for displaying the scores, so I dropped the GridLayout
in favour of GridBagLayout
. I positioned properly the new JPanel
for the scores and added 2 JTextArea
in it for displaying the results.
The thing is that each time one of the players will make a move(and hence the board gets redrawn to reflect its new state) the text areas will flicker and be partially covered by the board(see screenshot). Any idea what the issue might be? I have set the preferred size of all the components and tried using setOpaque
but it was to no avail.
The code of the main layout holder.
public class BoardLayout extends JFrame implements ModelObserver {
/**
* {@value}
*/
private static final long serialVersionUID = 5834762299789973250L;
/**
* {@value}
*/
private static final int RESULTS_PANEL_HEIGHT = 100;
private final BoardEventsListener eventsListener;
private final ResultsLayout resultsLayout;
private class CellMouseListener implements MouseListener {
private final int cellIndex;
public CellMouseListener(final int index) {
cellIndex = index;
}
@Override
public void mouseClicked(final MouseEvent event) {
eventsListener.onCellSelected(cellIndex);
}
@Override
public void mouseEntered(final MouseEvent event) {
// blank
}
@Override
public void mouseExited(final MouseEvent event) {
// blank
}
@Override
public void mousePressed(final MouseEvent event) {
// blank
}
@Override
public void mouseReleased(final MouseEvent event) {
// blank
}
}
public BoardLayout(final BoardEventsListener listener) throws HeadlessException {
this(listener, "", null);
}
public BoardLayout(GraphicsConfiguration graphicsConfiguration) {
this(null, "", graphicsConfiguration);
}
public BoardLayout(final BoardEventsListener listener, String title,
GraphicsConfiguration graphicsConfiguration) {
super(title, graphicsConfiguration);
eventsListener = listener;
setLayout(new GridBagLayout());
setBoardSize();
populateCells();
resultsLayout = attachResultsLayout();
resultsLayout.setOpaque(true);
setVisible(true);
}
private ResultsLayout attachResultsLayout() {
final ResultsLayout resultsLayout = new ResultsLayout(Game.BOARD_COLUMN_COUNT
* BoardCellLayout.WIDTH_BOARD_CELL, RESULTS_PANEL_HEIGHT);
final GridBagConstraints constraints = new GridBagConstraints();
constraints.gridwidth = GridBagConstraints.REMAINDER;
constraints.gridheight = GridBagConstraints.REMAINDER;
constraints.gridx = 0;
constraints.gridy = 8;
getContentPane().add(resultsLayout, constraints, 64);
return resultsLayout;
}
private void setBoardSize() {
final Dimension boardDimension = getBoardDimension();
setMinimumSize(boardDimension);
setSize(boardDimension);
setResizable(false);
}
private void populateCells() {
final Container container = getContentPane();
for (int i = 0; i < Game.BOARD_ROW_COUNT; ++i) {
for (int j = 0; j < Game.BOARD_COLUMN_COUNT; ++j) {
final BoardCellLayout currentCell = new BoardCellLayout();
final int cellIndex = i * Game.BOARD_COLUMN_COUNT + j;
final GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = j;
constraints.gridy = i;
container.add(currentCell, constraints, cellIndex);
currentCell.setOpaque(true);
currentCell.addMouseListener(new CellMouseListener(cellIndex));
}
}
}
private Dimension getBoardDimension() {
final Dimension boardDimension = new Dimension(Game.BOARD_COLUMN_COUNT
* BoardCellLayout.WIDTH_BOARD_CELL, (Game.BOARD_ROW_COUNT + 1)
* BoardCellLayout.HEIGHT_BOARD_CELL);
return boardDimension;
}
public BoardLayout(String title) throws HeadlessException {
this(null, title, null);
}
@Override
public void setVisible(final boolean isVisible) {
super.setVisible(isVisible);
setBackground(Color.WHITE);
pack();
}
@Override
public void onModelChanged(Collection<Cell> changedCells, final int whiteDiscsCount,
final int blackDiscsCount) {
for (final Cell cell : changedCells) {
final BoardCellLayout boardCell = getCellAt(cell.getIndex());
boardCell.take(cell.getOwner());
}
resultsLayout.onResultChanged(whiteDiscsCount, blackDiscsCount);
}
@Override
public void onNextMovesAcquired(Collection<Cell> nextMoves) {
clearCellHighlight();
for (final Cell cell : nextMoves) {
final BoardCellLayout boardCell = getCellAt(cell.getIndex());
boardCell.highlight();
}
}
private void clearCellHighlight() {
final Container container = getContentPane();
for (int i = 0; i < container.getComponentCount() - 1; ++i) {
final BoardCellLayout boardCellLayout = (BoardCellLayout) container.getComponent(i);
boardCellLayout.clearHighlight();
}
}
private BoardCellLayout getCellAt(final int index) {
final Container container = getContentPane();
return (BoardCellLayout) container.getComponent(index);
}
}
Code of the panel, holding the results:
public class ResultsLayout extends JPanel {
/**
* {@value}
*/
private static final long serialVersionUID = 8379710427718395507L;
private final ResultsTextView whiteTextView;
private final ResultsTextView blackTextView;
public ResultsLayout(final int width, final int height) {
super(new GridLayout(2, 1));
setVisible(true);
final Dimension dimension = new Dimension(width, height);
setMinimumSize(dimension);
setPreferredSize(dimension);
setSize(dimension);
whiteTextView = new ResultsTextView(Player.WHITE);
blackTextView = new ResultsTextView(Player.BLACK);
add(whiteTextView, 0);
add(blackTextView, 1);
}
public void onResultChanged(final int whiteDiscsCount, final int blackDiscsCount) {
whiteTextView.setDiscCount(whiteDiscsCount);
blackTextView.setDiscCount(blackDiscsCount);
}
}
Code of the JTextArea, holding the result:
public class ResultsTextView extends JTextArea {
/**
* {@value}
*/
private static final long serialVersionUID = -6354085779793155063L;
/**
* {@value}
*/
public static final String BACKGROUND_COLOR = "#066f02";
private static final int START_DISCS_NUMBER = 2;
private final Player player;
public ResultsTextView(final Player player) {
super();
setEditable(false);
setBackground(Color.decode(BACKGROUND_COLOR));
this.player = player;
setText(player.toString() + " result is: " + START_DISCS_NUMBER);
final Dimension dimension = new Dimension(100, 20);
setPreferredSize(dimension);
setMinimumSize(dimension);
setMaximumSize(dimension);
}
public void setDiscCount(final int discCount) {
setText(player.toString() + " result is:" + discCount);
}
}
Problem was that I was not using SwingUtilities.invokeLater
for updating the GUI and that was causing the flickering. I started using it and it's all fine now :)