1

I have some code for a Scrabble Game I am writing (actually rewriting), and it is split up into 3 classes so far. The Tile class seems to be generating a BorderFactory artifact when it is put in the window. Why is this artifact appearing, and how can I eliminate it?

*If you don't see the artifact, try resizing the window slowly.

Here is the Scrabble class.

import javax.swing.JFrame;
import java.awt.BorderLayout;
public class Scrabble extends JFrame implements Runnable
{
  public Board board;
  public Scrabble()
  {
    super("Scrabble!");
    board = new Board();
    addBorderLayoutObjects();
  }
  public void run()
  {
    makeSettings();
    setVisible(true);
  }
  public void makeSettings()
  {
    setSize(850, 900);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    //this.setResizable(false);
  }
  public void addBorderLayoutObjects()
  {
    getContentPane().add(BorderLayout.CENTER, board);
  }
  public static void main(String[] args)
  {
    Scrabble s = new Scrabble();
    javax.swing.SwingUtilities.invokeLater(s);
  }
}

Here is the Board class.

import javax.swing.JPanel;
import java.awt.Point;
import java.awt.Color;
import java.awt.GridLayout;
public class Board extends JPanel
{
  public Tile [][] board;
  public Board()
  {
    super(new GridLayout(15, 15));
    board = new Tile[15][15];
    makeBoard();
  }
  public void makeBoard()
  {
    for(int k = 0; k < 225; k++)
    {
      board[k/15][k%15] = new Tile(new Color(0xCBC4A8), Color.BLACK);
    }
    for(int a = 0; a < 15; a++)
      {
        for(int l = 0; l < 15; l++)
        {
          add(board[a][l]);
        }
      }
  }
}

And the Tile class.

import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Point;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
public class Tile extends JPanel implements MouseListener
{
  private Color color;
  private Color border;
  public Tile(Color _color, Color _border)
  {
    color = _color;
    border = _border;
  }
  public void mouseEntered(MouseEvent e){}
  public void mouseExited(MouseEvent e){}
  public void mousePressed(MouseEvent e){}
  public void mouseReleased(MouseEvent e){}
  public void mouseClicked(MouseEvent e){}
  @Override
  public void paintComponent(Graphics g)
  {
    g.setColor(color);
    setBorder(BorderFactory.createLineBorder(border, 2));
  }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
reesjones
  • 704
  • 3
  • 9
  • 28
  • I'm not sure I understand your issue, what exactly is the problem with the Tile's Border ? – Gil Peretz Feb 14 '13 at 07:10
  • When the window is resized, or even just drawn, there appear to be two borders created for each tile, that adjust their sizes slightly differently. Here is a screenshot of the artifact: http://imgur.com/vbfnvPN – reesjones Feb 14 '13 at 07:13
  • I think it might have to do with the fact that it invokes the method createLineBorder() every time it repaints, which to me implies that it makes multiple borders. I'm not sure how to fix this though. – reesjones Feb 14 '13 at 07:28

1 Answers1

1

This is your first problem (and possibly your second)

public void paintComponent(Graphics g)
{
    g.setColor(color);
    setBorder(BorderFactory.createLineBorder(border, 2));
}

Firstly, you must call super.paintComponent or take responsibility for its actions. This will clear and prepare the Graphics context for further painting.

Secondly, you should never modify any UI component from within a paintXxx method that may cause it be invalidated or repainted. Doing so will end you an infinite loop of burning CPU...

Set the border within the constructor or change it as the program needs, do not do so from within the paint method...

Updated with additional examples

When you need to change the border, simply call setBorder on the instance of the title you want change....

public Tile(Color _color, Color _border)
{
    color = _color;
    border = _border;
    setBorder(BorderFactory.createLineBorder(border, 2));
}

or

Title tile = new Tile(Color.RED, Color.BLUE);
//...
title.setBorder(BorderFactory.createLineBorder(Color.GREEN, 2));

Check out How to use borders for more info...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Calling super.paintComponent(g) removed the artifact. How do I change the border without putting it in the paintComponent method? – reesjones Feb 14 '13 at 22:57
  • Calling setBorder in a paint method causes heavy CPU load. You should not set anything to the component in a paint method, because this causes a repaint, which sets the border again, which causes a repaint again and so on ;) – JavaDM May 28 '15 at 16:01
  • @WEBALDO.at Isn't that what I said? *"Secondly, you should never modify any UI component from within a paintXxx method that may cause it be invalidated or repainted. Doing so will end you an infinite loop of burning CPU..."* – MadProgrammer May 28 '15 at 21:13