javaswingtablecellrenderer

Icon in JTable Cell Causing Misrendering


I'm trying to use a custom renderer to set the background of individual cells to a given image. In this case, I'm giving a chessboard wooden squares.

Here's what it looks like before:

https://i.sstatic.net/i85nG.jpg

Here's what it looks like afterwards:

https://i.sstatic.net/Ho4Q5.jpg

EDIT: With a little experimentation, it seems that every square is given the wood icon. Pieces can still be moved, resulting in this: (put it in the comments because I can't post more than 2 links)

In my code, I've merely replaced the setBackground(darkSquare) with setIcon(wood).

@SuppressWarnings("serial")
public class BoardCellRenderer extends DefaultTableCellRenderer {

    private ArrayList<Coordinate> possibleMoves = new ArrayList<Coordinate>();
    private ImageIcon wood = new ImageIcon("resources/images/light_square.png");

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        setHorizontalAlignment(SwingConstants.CENTER);

        Color darkSquare = new Color(125, 125, 125);

        //pattern for the chessboard look
        if(row % 2 == 0 && column % 2 == 1)
            setBackground(darkSquare);
            //setIcon(wood);
        else if(row % 2 == 1 && column % 2 == 0)
            setBackground(darkSquare);
            //setIcon(wood);
        else
            setBackground(Color.WHITE);

        for(Coordinate move : possibleMoves)
            if(column == move.getX() && row == move.getY()){
                setBackground(new Color(255, 51, 51, 50));
                System.out.println("Highlighting (" + row + ", " + column + ")");
            }

        if(hasFocus){
            setBorder(new MatteBorder(2, 2, 2, 2, Color.RED));
            System.out.println("hasFocus [array]: " + row + ", " + column);
            System.out.println("hasFocus [coordinate]: " + column + ", " + row);
        }
        if(isSelected)
            setBorder(new MatteBorder(2, 2, 2, 2, Color.BLUE));


        return this;
    }

    public void setPossibleMoves(ArrayList<Coordinate> possibleMoves){
        this.possibleMoves = possibleMoves;
    }
}

Solution

  • it seems that every square is given the wood icon.

    The renderer remembers its last state.

    So maybe something like:

    //  set the default values
    
    setBackground(Color.WHITE); 
    setIcon(null);  
    
    if(row % 2 == 0 && column % 2 == 1)
        //setBackground(darkSquare);
        setIcon(wood);
    else if(row % 2 == 1 && column % 2 == 0)
        //setBackground(darkSquare);
        setIcon(wood);
    

    Of course you will still have a problem when you want to display a chess piece on top of the wood as you will want to render two icons, one for the background and one for the chess piece.

    I'm not sure if a JTable is the best component to use for this. It might be easier to use a JPanel with a grid of either JPanel/JLabel to represent the wood square. Then you add a JLabel with an Icon of the chess piece to the square. This posting of a simple Chess Board might give you some ideas.

    Edit:

    Would that be why the cell looks like it's printing ...?

    Probably. The default for a JLabel is to display the icon followed by the text.

    You can change this behaviour by using:

    setHorizontalTextPosition(JLabel.CENTER);
    setVerticalTextPosition(JLabel.CENTER);
    

    in the constructor of your renderer. Then the text will be centered over the icon.