@Override
    protected void paintComponent(Graphics oldG) {
        super.paintComponent(oldG);
        if (fullBoard == null) {
            return;
        }
        //Calculate necessary cell width and height to fill panel
        cellWidth = getWidth() / (fullBoard.getColumns() - (zoomFactor * 2));
        cellHeight = getHeight() / (fullBoard.getColumns() - (zoomFactor * 2));
        Graphics2D g = (Graphics2D) oldG;
        //Skip rows and columns that aren't within view after zooming
        for (int r = zoomFactor; r < fullBoard.getRows() - zoomFactor; r++) {
            for (int c = zoomFactor; c < fullBoard.getColumns() - zoomFactor; c++) {
                //Get the contents of the square that corresponds with this cell
                Square square = fullBoard.getCell(r, c);
                //Perform whatever operations you want, give the square's info
                //For my example I only fill in the cell if it is not null
                if (square != null) {
                    //Build cell outline
                    Rectangle outline = new Rectangle(
                            (c - zoomFactor) * cellWidth, (r - zoomFactor) * cellHeight, cellWidth, cellHeight);
                    //Set cell outline color
                    g.setColor(java.awt.Color.black);
                    //Draw the cell outline
                    g.draw(outline);
                    //Build cell shape (the 1 offsets allow for the outline to be visible)
                    //Subtracting the zoom ofset makes sure the cells render properly
                    Rectangle cell = new Rectangle(
                            (c - zoomFactor) * cellWidth + 1, (r - zoomFactor) * cellHeight + 1, cellWidth - 1, cellHeight - 1);
                    //Set the color for the inside of the cell
                    g.setColor(java.awt.Color.white);
                    //Fill the square
                    g.fill(cell);
                }
            }
        }
    }