Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make my custom Swing component visible?

Tags:

java

swing

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?

like image 407
Smooth Operator Avatar asked Nov 19 '25 22:11

Smooth Operator


2 Answers

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);
     }
}
like image 158
camickr Avatar answered Nov 21 '25 12:11

camickr


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.

like image 40
Courtney Christensen Avatar answered Nov 21 '25 10:11

Courtney Christensen