Found this code in the internet, it was posted years ago, so I just decided to ask here for some clarifications for some lines I don't quite understand.
In the mousePressed method, what does he mean by:
chessPiece = null is he saying that if the JLabel chessPiece has a image in it then it should be changed to null?
Is chessBoard.findComponentAt(e.getX(), e.getY()) returns the JPanel square?
and lastly, when Component c gets its parent, who is the parent?
The whole code is below:
public class ChessGameDemo extends JFrame implements MouseListener, MouseMotionListener {
JLayeredPane layeredPane;
JPanel chessBoard;
JLabel chessPiece;
int xAdjustment;
int yAdjustment;
private static final String imageFolderPath = "src/resources/images/";
public ChessGameDemo() {
Dimension boardSize = new Dimension(600, 600);
// Use a Layered Pane for this this application
layeredPane = new JLayeredPane();
getContentPane().add(layeredPane);
layeredPane.setPreferredSize(boardSize);
layeredPane.addMouseListener(this);
layeredPane.addMouseMotionListener(this);
//Add a chess board to the Layered Pane
chessBoard = new JPanel();
layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);
chessBoard.setLayout(new GridLayout(8, 8));
chessBoard.setPreferredSize(boardSize);
chessBoard.setBounds(0, 0, boardSize.width, boardSize.height);
for (int i = 0; i < 64; i++) {
JPanel square = new JPanel(new BorderLayout());
chessBoard.add(square);
int row = (i / 8) % 2;
if (row == 0) {
square.setBackground(i % 2 == 0 ? Color.blue : Color.white);
} else {
square.setBackground(i % 2 == 0 ? Color.white : Color.blue);
}
}
//Add a few pieces to the board
JLabel piece = new JLabel(new ImageIcon(imageFolderPath + "/pieces/bdg.png"));
JPanel panel = (JPanel) chessBoard.getComponent(0);
panel.add(piece);
piece = new JLabel(new ImageIcon(imageFolderPath + "/pieces/belder.png"));
panel = (JPanel) chessBoard.getComponent(15);
panel.add(piece);
piece = new JLabel(new ImageIcon(imageFolderPath + "/pieces/bhero.png"));
panel = (JPanel) chessBoard.getComponent(16);
panel.add(piece);
piece = new JLabel(new ImageIcon(imageFolderPath + "/pieces/borb.png"));
panel = (JPanel) chessBoard.getComponent(20);
panel.add(piece);
}
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);
chessPiece.setSize(chessPiece.getWidth(), chessPiece.getHeight());
layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);
}
//Move the chess piece around
public void mouseDragged(MouseEvent me) {
if (chessPiece == null) {
return;
}
chessPiece.setLocation(me.getX() + xAdjustment, me.getY() + yAdjustment);
}
//Drop the chess piece back onto the chess board
public void mouseReleased(MouseEvent e) {
if (chessPiece == null) {
return;
}
chessPiece.setVisible(false);
Component c = chessBoard.findComponentAt(e.getX(), e.getY());
if (c instanceof JLabel) {
Container parent = c.getParent();
parent.remove(0);
parent.add(chessPiece);
} else {
Container parent = (Container) c;
parent.add(chessPiece);
}
....
}
In the mousePiece method, what does he mean by: chessPiece = null is
he saying that if the JLabel chessPiece has a image in it then it
should be changed to null?
I assume you mean mousePressed. By using chessPiece = null, the author is de-referencing the variable, so what ever was assigned to it is no longer reachable through the is variable
Is chessBoard.findComponentAt(e.getX(), e.getY()) returns the JPanel square?
This depends. findComponentAt can search the current container and it's any of it's child containers until it finds a component at the specified position. Technquial, the author is ignoring the component that triggered the event (which should layeredPane) and is walking the chessBoard instead. I suspect they are doing this because if they used layeredPane it would return chessBoard instead.
The method is capable of returning JPanel, JLabel and possibly even null, but given the way that the components are laid out, it's a lower probability.
and lastly, when Component c gets its parent, who is the parent?
This depends. Based on my understanding of the code, I would say it's return a JPanel underneth the JLabel piece.
Have to say, there are easier ways to achieve the same result though...
In the mousePressed method, what does he mean by:
The purpose of the class is to drag a label from one square to another. So there is code in the mouseDragged and mouseReleased events to 1) do the dragging of the label on the layered pane and 2) drop the label onto the appropriate square.
However, if the user didn't click on a square containing a label then the above code should not be executed, so the chessPiece is initially set to null and the code in the above two method is only executed when a chessPiece was clicked on.
Is chessBoard.findComponentAt(e.getX(), e.getY()) returns the JPanel square?
If it returns a JPanel, then that means there is NO chessPiece (JLabel) on the square where the user clicked. Since there is no chessPiece there is nothing to be dragged.
If it returns a JLabel, then that means there IS a chessPiece where the user clicked. In this case addition code is executed to add the chessPiece to the layered pane so it can be dragged.
when Component c gets its parent, who is the parent?
It's the JPanel containing the label. Since the label is added to the layered pane for dragging it needs to be positioned at the same location on the layered pane relative to the panel square on the chessboard.
Here is a slightly updated version that checks the bounds of the chess piece as it is dragged so it can't be moved off of the chess board. Also adds the mouse listeners to the chess board not the layered pane so the findComponentAt() method is more consistent.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class ChessBoard extends JLayeredPane implements MouseListener, MouseMotionListener
{
JLayeredPane layeredPane;
JPanel chessBoard;
JLabel chessPiece;
int xAdjustment;
int yAdjustment;
public ChessBoard()
{
Dimension boardSize = new Dimension(600, 600);
setPreferredSize( boardSize );
// 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);
chessBoard.addMouseListener( this );
chessBoard.addMouseMotionListener( this );
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);
add(chessPiece, JLayeredPane.DRAG_LAYER);
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 = chessBoard.getWidth() - chessPiece.getWidth();
x = Math.min(x, xMax);
x = Math.max(x, 0);
int y = me.getY() + yAdjustment;
int yMax = chessBoard.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)
{
setCursor(null);
if (chessPiece == null) return;
// Make sure the chess piece is no longer painted on the layered pane
chessPiece.setVisible(false);
remove(chessPiece);
chessPiece.setVisible(true);
// The drop location should be within the bounds of the chess board
int xMax = chessBoard.getWidth() - chessPiece.getWidth();
int x = Math.min(e.getX(), xMax);
x = Math.max(x, 0);
int yMax = chessBoard.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.revalidate();
}
else
{
Container parent = (Container)c;
parent.add( chessPiece );
parent.revalidate();
}
}
public void mouseClicked(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
private static void createAndShowUI()
{
JFrame frame = new JFrame("Chess Board");
frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
frame.add( new ChessBoard() );
frame.setResizable( false );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Related
I have an array of JTextPanes inside JScrollPanes. All those components I mentioned are inside a JPanel inside a JScrollPane.
At the start of the program, none of the JTextPanes have any text, so the scrollbars for them are not visible. The scrollbars for the JPanel are visible, because I have a lot of components in it.
My issue is that if the cursor is over one of the JTextPanes and I try to scroll, nothing happens because the computer thinks I want to scroll with the JTextPane's scrollbars. What I would like to happen is for the computer to realize that I'm trying to scroll with the JPanel's scrollbar. Is there any way I could accomplish this?
Thanks!
Edit:
You could produce a similar UI to the one above with this code ( this is the constructor of a class extending JFrame - apologies for ignoring a lot of good coding habits ):
public JFrameTest() {
JPanel panel = new JPanel( new GridLayout( 10 , 10 , 10 , 10 ) );
for ( int i = 0 ; i < 10 ; i ++ ) {
for ( int j = 0 ; j < 10 ; j ++ ) {
JScrollPane paneToAdd = new JScrollPane( new JTextPane() ) {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension( 100 , 100 );
}
};
panel.add( paneToAdd );
}
}
add( new JScrollPane( panel ) );
setSize( 700 , 500 );
setVisible( true );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
The following code was taken as a quick hack from Mouse Wheel Controller.
Basically it intercepts the MouseWheelEvent for the scroll pane containing the text area. If the scrollbar is visible it redispatches the event back to the same scroll pane otherwise it finds the parent scrollPane and dispatches the event to that scrollPane.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MouseWheelToParent implements MouseWheelListener
{
private JScrollPane scrollPane;
private MouseWheelListener[] realListeners;
public MouseWheelToParent(JScrollPane scrollPane)
{
this.scrollPane = scrollPane;
install();
}
public void install()
{
if (realListeners != null) return;
// Keep track of original listeners so we can use them to
// redispatch an altered MouseWheelEvent
realListeners = scrollPane.getMouseWheelListeners();
for (MouseWheelListener mwl : realListeners)
{
scrollPane.removeMouseWheelListener(mwl);
}
// Intercept events so they can be redispatched
scrollPane.addMouseWheelListener(this);
}
/**
* Remove the class as the default listener and reinstall the original
* listeners.
*/
public void uninstall()
{
if (realListeners == null) return;
// Remove this class as the default listener
scrollPane.removeMouseWheelListener( this );
// Install the default listeners
for (MouseWheelListener mwl : realListeners)
{
scrollPane.addMouseWheelListener( mwl );
}
realListeners = null;
}
// Implement MouseWheelListener interface
/**
* Redispatch a MouseWheelEvent to the real MouseWheelListeners
*/
public void mouseWheelMoved(MouseWheelEvent e)
{
// System.out.println(e.getScrollType() + " : " + e.getScrollAmount() + " : " + e.getWheelRotation());
JScrollPane scrollPane = (JScrollPane)e.getComponent();
if (scrollPane.getVerticalScrollBar().isVisible())
{
// Redispatch the event to original MouseWheelListener
for (MouseWheelListener mwl : realListeners)
{
mwl.mouseWheelMoved( e );
}
}
else
{
dispatchToParent(e, scrollPane);
return;
}
}
private void dispatchToParent(MouseWheelEvent e, JScrollPane scrollPane)
{
Component ancestor = SwingUtilities.getAncestorOfClass(JScrollPane.class, scrollPane);
MouseWheelEvent mwe = new MouseWheelEvent(
ancestor,
e.getID(),
e.getWhen(),
e.getModifiersEx(),
e.getX(),
e.getY(),
e.getXOnScreen(),
e.getYOnScreen(),
e.getClickCount(),
e.isPopupTrigger(),
e.getScrollType(),
e.getScrollAmount(),
e.getWheelRotation());
ancestor.dispatchEvent(mwe);
}
private static void createAndShowUI()
{
JPanel panel = new JPanel( new GridBagLayout() );
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(10, 10, 10, 10);
for (int y = 0; y < 10; y++)
{
for (int x = 0; x < 5; x++)
{
gbc.gridx = x;
gbc.gridy = y;
JTextArea textArea = new JTextArea(5, 20);
JScrollPane scrollPane = new JScrollPane( textArea );
scrollPane.setMinimumSize( scrollPane.getPreferredSize() );
new MouseWheelToParent(scrollPane);
panel.add(scrollPane, gbc);
if (x == 0 && y ==0)
{
textArea.append("1\n2\n3\n4\n5\n6\n7\n8\n9");
textArea.setCaretPosition(0);
}
}
}
JFrame frame = new JFrame("TextAreaSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new JScrollPane( panel ) );
frame.setSize(400, 400);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
I have an array of JTextPanes inside JScrollPanes. All those components I mentioned are inside a JPanel inside a JScrollPane.
At the start of the program, none of the JTextPanes have any text, so the scrollbars for them are not visible. The scrollbars for the JPanel are visible, because I have a lot of components in it.
My issue is that if the cursor is over one of the JTextPanes and I try to scroll, nothing happens because the computer thinks I want to scroll with the JTextPane's scrollbars. What I would like to happen is for the computer to realize that I'm trying to scroll with the JPanel's scrollbar. Is there any way I could accomplish this?
Thanks!
Edit:
You could produce a similar UI to the one above with this code ( this is the constructor of a class extending JFrame - apologies for ignoring a lot of good coding habits ):
public JFrameTest() {
JPanel panel = new JPanel( new GridLayout( 10 , 10 , 10 , 10 ) );
for ( int i = 0 ; i < 10 ; i ++ ) {
for ( int j = 0 ; j < 10 ; j ++ ) {
JScrollPane paneToAdd = new JScrollPane( new JTextPane() ) {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension( 100 , 100 );
}
};
panel.add( paneToAdd );
}
}
add( new JScrollPane( panel ) );
setSize( 700 , 500 );
setVisible( true );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
The following code was taken as a quick hack from Mouse Wheel Controller.
Basically it intercepts the MouseWheelEvent for the scroll pane containing the text area. If the scrollbar is visible it redispatches the event back to the same scroll pane otherwise it finds the parent scrollPane and dispatches the event to that scrollPane.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MouseWheelToParent implements MouseWheelListener
{
private JScrollPane scrollPane;
private MouseWheelListener[] realListeners;
public MouseWheelToParent(JScrollPane scrollPane)
{
this.scrollPane = scrollPane;
install();
}
public void install()
{
if (realListeners != null) return;
// Keep track of original listeners so we can use them to
// redispatch an altered MouseWheelEvent
realListeners = scrollPane.getMouseWheelListeners();
for (MouseWheelListener mwl : realListeners)
{
scrollPane.removeMouseWheelListener(mwl);
}
// Intercept events so they can be redispatched
scrollPane.addMouseWheelListener(this);
}
/**
* Remove the class as the default listener and reinstall the original
* listeners.
*/
public void uninstall()
{
if (realListeners == null) return;
// Remove this class as the default listener
scrollPane.removeMouseWheelListener( this );
// Install the default listeners
for (MouseWheelListener mwl : realListeners)
{
scrollPane.addMouseWheelListener( mwl );
}
realListeners = null;
}
// Implement MouseWheelListener interface
/**
* Redispatch a MouseWheelEvent to the real MouseWheelListeners
*/
public void mouseWheelMoved(MouseWheelEvent e)
{
// System.out.println(e.getScrollType() + " : " + e.getScrollAmount() + " : " + e.getWheelRotation());
JScrollPane scrollPane = (JScrollPane)e.getComponent();
if (scrollPane.getVerticalScrollBar().isVisible())
{
// Redispatch the event to original MouseWheelListener
for (MouseWheelListener mwl : realListeners)
{
mwl.mouseWheelMoved( e );
}
}
else
{
dispatchToParent(e, scrollPane);
return;
}
}
private void dispatchToParent(MouseWheelEvent e, JScrollPane scrollPane)
{
Component ancestor = SwingUtilities.getAncestorOfClass(JScrollPane.class, scrollPane);
MouseWheelEvent mwe = new MouseWheelEvent(
ancestor,
e.getID(),
e.getWhen(),
e.getModifiersEx(),
e.getX(),
e.getY(),
e.getXOnScreen(),
e.getYOnScreen(),
e.getClickCount(),
e.isPopupTrigger(),
e.getScrollType(),
e.getScrollAmount(),
e.getWheelRotation());
ancestor.dispatchEvent(mwe);
}
private static void createAndShowUI()
{
JPanel panel = new JPanel( new GridBagLayout() );
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(10, 10, 10, 10);
for (int y = 0; y < 10; y++)
{
for (int x = 0; x < 5; x++)
{
gbc.gridx = x;
gbc.gridy = y;
JTextArea textArea = new JTextArea(5, 20);
JScrollPane scrollPane = new JScrollPane( textArea );
scrollPane.setMinimumSize( scrollPane.getPreferredSize() );
new MouseWheelToParent(scrollPane);
panel.add(scrollPane, gbc);
if (x == 0 && y ==0)
{
textArea.append("1\n2\n3\n4\n5\n6\n7\n8\n9");
textArea.setCaretPosition(0);
}
}
}
JFrame frame = new JFrame("TextAreaSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new JScrollPane( panel ) );
frame.setSize(400, 400);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
public class mouse extends JFrame {
private int x, y;
private JLabel label;
public mouse() {
JPanel panel = new JPanel();
addMouseMotionListener(new MouseMotion());
label = new JLabel();
panel.add(label);
setPreferredSize(new Dimension(400, 200));
add(panel, BorderLayout.SOUTH);
pack();
setVisible(true);
}
private class MouseMotion extends MouseMotionAdapter {
public void mouseMoved(MouseEvent e) {
x = e.getX();
y = e.getY();
label.setText("mouse coordinate " + "(" + x + "," + y + ")");
}}
public static void main(String[]args) {
mouse a = new mouse();
}
}
When I move mouse to border, it is not (0,0). Why? For example, I move mouse to top left corner, it shows (4,30) rather than (0,0).
Add the MouseListener or MouseMotionListener to the JFrame's contentPane, not the JFrame itself, else you have to worry about borders, menus, insets, and the like. For example:
getContentPane().addMouseMotionListener(new MouseMotion());
Also, please format your code so we can read it.
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?
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);
}
}
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.
This question is related to my previous question How to generate Cartesian Coordinate (x,y) from GridBaglayout?
I have successfully get the coordinate of each pictures, however when I checked the coordinate through (System.out.println) and the placement of the images on the screen, it seems to be wrong. e.g. if on the screen it was obvious that the x point of the first picture is on cell 2 which is on coordinate of 20, but the program shows x=1.
Here is part of the code:
public Grid (){
setPreferredSize(new Dimension(600,600));
....
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.weightx = 1d;
gc.weighty = 1d;
gc.insets = new Insets(0, 0, 0, 0);//top, left, bottom, and right
gc.fill = GridBagConstraints.BOTH;
JLabel[][] label = new JLabel[ROWS][COLS];
Random rand = new Random();
// fill the panel with labels
for (int i=0;i<IMAGES;i++){
ImageIcon icon = createImageIcon("myPics.jpg");
int r, c;
do{
//pick random cell which is empty
r = (int)Math.floor(Math.random() * ROWS);
c = (int)Math.floor(Math.random() * COLS);
} while (label[r][c]!=null);
//randomly scale the images
int x = rand.nextInt(50)+30;
int y = rand.nextInt(50)+30;
Image image = icon.getImage().getScaledInstance(x,y, Image.SCALE_SMOOTH);
icon.setImage(image);
JLabel lbl = new JLabel(icon); // Instantiate GUI components
gc.gridx = r;
gc.gridy = c;
add(lbl, gc); //add(component, constraintObj);
label[r][c] = lbl;
}
I checked the coordinate through this code:
Component[] components = getComponents();
for (Component component : components) {
System.out.println(component.getBounds());
}
You can use SwingUtilities convertPointToScreen() and convertPointFromScreen() to convert between screen and component coordinates.
Addendum: Here's a simple example I used when trying to understand how components move and resize under the influence of a layout manager.
public class MyPanel extends JPanel {
public MyPanel() {
super(new GridLayout(4, 4));
for (int i = 0; i < 16; i++) {
JPanel panel = new JPanel(new GridLayout());
panel.add(new CenterLabel());
this.add(panel);
}
}
private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
create();
}
});
}
private static class CenterLabel extends JLabel {
public CenterLabel() {
this.setHorizontalAlignment(JLabel.CENTER);
this.setVerticalAlignment(JLabel.CENTER);
this.setOpaque(true);
this.setBackground(Color.lightGray);
this.setBorder(BorderFactory.createLineBorder(Color.blue));
this.setPreferredSize(new Dimension(160, 100));
this.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
int w = e.getComponent().getWidth();
int h = e.getComponent().getHeight();
CenterLabel.this.setText("[" + w/2 + "\u253C" + h/2 + "]");
}
});
}
}
}
if on the screen it was obvious that
the x point of the first picture is on
cell 2 which is on coordinate of 20,
but the program shows x=1.
The first image will have x/y coordinates of 0/0. The second images will have coordinates of 1/0. The X/Y values of offset from 0. Is that what you are talking about?
Or is your listener added to the image not the panel in which case you need to convert the image coordinates to the panel coordinates. Check our the SwingUtilities class for methods to do this.
If you need more help post your SSCCE.