3

I have no idea why it won't show. First I create an instance of the component and then add it to a certain element in a two-dimensional JPanel array. Then I loop through that array and add each JPanel to another JPanel container which is to hold all the JPanels.

I then add that final container to my JFrame window and set visibility to true, it should be visible?

public class View extends JFrame {

    Board      gameBoard;
    JFrame     gameWindow   = new JFrame("Chess");
    JPanel     gamePanel    = new JPanel();
    JPanel[][] squarePanel  = new JPanel[8][8];
    JMenuBar   gameMenu     = new JMenuBar();
    JButton    restartGame  = new JButton("Restart");
    JButton    pauseGame    = new JButton("Pause");
    JButton    log          = new JButton("Log");

    View(Board board){
        gameWindow.setDefaultCloseOperation(EXIT_ON_CLOSE);
        gameWindow.setSize(400, 420);
        gameWindow.getContentPane().add(gamePanel, BorderLayout.CENTER);
        gameWindow.getContentPane().add(gameMenu, BorderLayout.NORTH);
        gameMenu.add(restartGame);
        gameMenu.add(pauseGame);
        gameMenu.add(log);
        gameBoard = board;
        drawBoard(gameBoard);
        gameWindow.setResizable(false);
        gameWindow.setVisible(true);

    }

    public void drawBoard(Board board){
        for(int row = 0; row < 8; row++){
            for(int col = 0; col < 8; col++){
                Box box = new Box(board.getSquare(col, row).getColour(), col, row);
                squarePanel[col][row] = new JPanel();
                squarePanel[col][row].add(box);
            }
        }
        for(JPanel[] col : squarePanel){
            for(JPanel square : col){
                gamePanel.add(square);
            }
        }
    }
}

@SuppressWarnings("serial")
class Box extends JComponent{
    Color boxColour;
    int col, row;
    public Box(Color boxColour, int col, int row){
        this.boxColour = boxColour;
        this.col = col;
        this.row = row;
        repaint();
    }
    protected void paintComponent(Graphics drawBox){
        drawBox.setColor(boxColour);
        drawBox.drawRect(50*col, 50*row, 50, 50);
        drawBox.fillRect(50*col, 50*row, 50, 50);
    }
}

A final question as well. Notice how each Box component has a position, what happens to the position when I add the component to a JPanel and add the JPanel to my JFrame? Does it still have the same position in relation to the other Box components?

Smooth Operator
  • 197
  • 2
  • 4
  • 15
  • Where is your `main`? `View`'s constructor is never called, as far as I can tell. Also, the class `View` is a `JFrame`, which is never made visible. – Courtney Christensen Jan 12 '11 at 21:37
  • Right, forgot to tell about that. The constructor is called in another class, Game, in which "board" is passed as an argument. Board holds a Square[][] and getSquare method get's the square at index col, row. The getColour method gets the squareColour attribute from the square. The board sets the squareColour in the constructor by looping through the array. – Smooth Operator Jan 12 '11 at 21:41
  • gameWindow is made visible? Also, what's weird is that my Menu is visible, and the buttons too. It's just the Boxes that aren't. – Smooth Operator Jan 12 '11 at 21:45

2 Answers2

5

I tried extending JPanel instead, got a small 10x10 pix gray box under my menu. Atleast a start

When you use a JComponent the preferred size is (0, 0) which is why you see nothing.

When you use a JPanel is uses a FlowLayout by default and the FlowLayout has a 5 pixel gap before/after each component added to the panel. Since you don't add any components the preffered size is just the gap so you get a size of (10, 10).

Therefore, when you do custom painting you need to override the getPreferredSize() method to return a proper value for the custom painting you intend to implement.

Edit:

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

public class ChessBoard extends JFrame implements MouseListener, MouseMotionListener
{
    JLayeredPane layeredPane;
    JPanel chessBoard;
    JLabel chessPiece;
    int xAdjustment;
    int yAdjustment;

    public ChessBoard()
    {
        Dimension boardSize = new Dimension(600, 600);

        //  Use a Layered Pane for this this application

        layeredPane = new JLayeredPane();
        layeredPane.setPreferredSize( boardSize );
        layeredPane.addMouseListener( this );
        layeredPane.addMouseMotionListener( this );
        getContentPane().add(layeredPane);

        //  Add a chess board to the Layered Pane

        chessBoard = new JPanel();
        chessBoard.setLayout( new GridLayout(8, 8) );
        chessBoard.setPreferredSize( boardSize );
        chessBoard.setBounds(0, 0, boardSize.width, boardSize.height);
        layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);

        //  Build the Chess Board squares

        for (int i = 0; i < 8; i++)
        {
            for (int j = 0; j < 8; j++)
            {
                JPanel square = new JPanel( new BorderLayout() );
                square.setBackground( (i + j) % 2 == 0 ? Color.red : Color.white );
                chessBoard.add( square );
            }
        }

        // Add a few pieces to the board

        ImageIcon duke = new ImageIcon("dukewavered.gif"); // add an image here

        JLabel piece = new JLabel( duke );
        JPanel panel = (JPanel)chessBoard.getComponent( 0 );
        panel.add( piece );
        piece = new JLabel( duke );
        panel = (JPanel)chessBoard.getComponent( 15 );
        panel.add( piece );
    }

    /*
    **  Add the selected chess piece to the dragging layer so it can be moved
    */
    public void mousePressed(MouseEvent e)
    {
        chessPiece = null;
        Component c =  chessBoard.findComponentAt(e.getX(), e.getY());

        if (c instanceof JPanel) return;

        Point parentLocation = c.getParent().getLocation();
        xAdjustment = parentLocation.x - e.getX();
        yAdjustment = parentLocation.y - e.getY();
        chessPiece = (JLabel)c;
        chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);

        layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);
        layeredPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    }

    /*
    **  Move the chess piece around
    */
    public void mouseDragged(MouseEvent me)
    {
        if (chessPiece == null) return;

        //  The drag location should be within the bounds of the chess board

        int x = me.getX() + xAdjustment;
        int xMax = layeredPane.getWidth() - chessPiece.getWidth();
        x = Math.min(x, xMax);
        x = Math.max(x, 0);

        int y = me.getY() + yAdjustment;
        int yMax = layeredPane.getHeight() - chessPiece.getHeight();
        y = Math.min(y, yMax);
        y = Math.max(y, 0);

        chessPiece.setLocation(x, y);
     }

    /*
    **  Drop the chess piece back onto the chess board
    */
    public void mouseReleased(MouseEvent e)
    {
        layeredPane.setCursor(null);

        if (chessPiece == null) return;

        //  Make sure the chess piece is no longer painted on the layered pane

        chessPiece.setVisible(false);
        layeredPane.remove(chessPiece);
        chessPiece.setVisible(true);

        //  The drop location should be within the bounds of the chess board

        int xMax = layeredPane.getWidth() - chessPiece.getWidth();
        int x = Math.min(e.getX(), xMax);
        x = Math.max(x, 0);

        int yMax = layeredPane.getHeight() - chessPiece.getHeight();
        int y = Math.min(e.getY(), yMax);
        y = Math.max(y, 0);

        Component c =  chessBoard.findComponentAt(x, y);

        if (c instanceof JLabel)
        {
            Container parent = c.getParent();
            parent.remove(0);
            parent.add( chessPiece );
            parent.validate();
        }
        else
        {
            Container parent = (Container)c;
            parent.add( chessPiece );
            parent.validate();
        }
    }

    public void mouseClicked(MouseEvent e) {}
    public void mouseMoved(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}

    public static void main(String[] args)
    {
        JFrame frame = new ChessBoard();
        frame.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
        frame.setResizable( false );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
     }
}
camickr
  • 321,443
  • 19
  • 166
  • 288
  • Great, thanks! Now I can somewhat see the squares, they have a gap so I have to change the layout to get rid of that right? Still they don't look right, if I have setOpaque to true they show up but without color and with a gap. If I don't run setOpaque however, I get a gray box and where the second box should be there's just a thick horizontal gray line. Also on the next row in the middle there's a dark gray/black vertical thick line followed by a dot of the same color. – Smooth Operator Jan 12 '11 at 22:38
  • You should not use Box as a component name. Swing already has a component by that name. Also, you don't need to create a custom component for this. You can just invoke the setBackground(...) method on the JPanel and it will paint the background for you. I included my chess board example for you to look at. I'm not sure what your problem is since the code is not complete. – camickr Jan 12 '11 at 22:49
  • Thanks for that, I tried using GridLayout. Pretty practical, however I added the JPanel with the squares to my View JFrame and it always seems to take up the whole window. I used pack(). I tried setting View's preferred size to something bigger then that of the JPanel with the board and the board is still taking up the whole window. Also, I noticed your square colors are reversed :P Most chess boards have the upper left square being white, if you use (i + j) % 2 == 0 it turns black, should be != 0. – Smooth Operator Jan 12 '11 at 23:59
1

In the past, I have solved this by extending JPanel instead of JComponent. I found an good example here. Here's an adaptation of it which will draw a box:

public class Box extends JPanel {
  Color color;

  public Box (Color c, int w, int h) {
    color = color;
    setSize(w, h);
  }

  @Override
  public void paintComponent(Graphics g) {
    g.setColor(color);
    g.drawOval(0, 0, getWidth(), getHeight());
 }

 ...

This isn't exactly like your code above, but hopefully it'll get you started in the right direction!

A quick note (original response): the example above View is a JFrame which is never made visible. Instead, the class variable gameWindow is used. It would be good practice to make the top-level class the visible window.

Courtney Christensen
  • 9,165
  • 5
  • 47
  • 56
  • Thanks! Problem remains though :/. – Smooth Operator Jan 12 '11 at 21:51
  • Ok, I understand the issue now -- the extended `JComponent` is not redrawing. Sorry. Seems like I've had a similar issue in the past and ended up extending `JPanel` instead...digging now! :-) – Courtney Christensen Jan 12 '11 at 21:55
  • Oh, at least I know what the problem is now :P I tried extending JPanel instead, got a small 10x10 pix gray box under my menu. Atleast a start! :p – Smooth Operator Jan 12 '11 at 22:08
  • I beg to differ and I warn the original poster to take zourtney's advice with a grain of salt. There is no repaintComponent method for JPanels either. Both classes have the paintComponent method though, and this method works the same for both classes. His code should work with using a JComponent as long as he follows rob camick's advice. – Hovercraft Full Of Eels Jan 12 '11 at 22:36
  • @Hovercraft, right, I just realized that (forehead slap!). I was confusing the `paintComponent()` and `repaint()` methods. Sorry. I tried to update my answer accordingly. – Courtney Christensen Jan 12 '11 at 22:40