How to redraw JButtons and update GUI for a chess game - java

I'm trying to make a chess game, but I can't figure out how to smoothly redraw my cells. I want them to be redrawn every time a Piece moves. I tried to just keep adding Jframes, but it makes it glitch back to old frames. Is there a simple way to just update some part of the GUI?
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class GUI {
public static JFrame frame; //global variable for drawn frame
public static ChessBoardPane tiles;
public GUI(final Piece[][] board) { //GUI for Board and Pieces
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
frame = new JFrame("Chess"); //initialize frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //closes on exit
drawFrame(board); //draw frame
}
});
}
public void drawFrame(final Piece[][] board){ //updates gui with a new frame
try{
tiles=new ChessBoardPane(board);
frame.add(tiles); //add chess board to frame
frame.pack(); //resizes frame to fit chess grid
frame.setLocationRelativeTo(null); //window in middle of screen
frame.setVisible(true); //visible
} catch(Exception ex){
}
}
public class ChessBoardPane extends JPanel{ //creates a grid of jButtons
public ChessBoardPane(Piece board[][]) {
int index = 0;
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
for (int row = 0; row < Board.width; row++) {
for (int col = 0; col < Board.height; col++) {
Color color = index % 2 == 0 ? Color.LIGHT_GRAY : Color.DARK_GRAY; //cells are dark and light gray
gbc.gridx = col;
gbc.gridy = row;
String symbol;
if(board[col][Board.height-row-1]!=null){
symbol=board[col][Board.height-row-1].symbol; //chooses the correct picture for a piece
}
else
symbol=null;
Cell tile = new Cell(color,symbol);
tile.addActionListener(new ButtonActionListener(col, Board.height-row-1));
add(tile, gbc); //add cell to gui
index++;
}
index++;
}
}
private class ButtonActionListener implements ActionListener{ //used to get x and y coordinates for button presses and call methods
private int x;
private int y;
public ButtonActionListener(int x, int y){
this.x=x;
this.y=y;
}
public void actionPerformed(ActionEvent e){ //runs commands when a tile is pressed
Game.attemptMove(x,y);
}
}
}
public class Cell extends JButton { //sets up cell behavior
int x;
int y;
public Cell(Color background, String symbol) {
setContentAreaFilled(false);
if(symbol!=null){
ImageIcon img = new ImageIcon(symbol); //puts picture in cell
setIcon(img);
}
setBorderPainted(false);
setBackground(background); //sets cell color
setOpaque(true);
}
#Override
public Dimension getPreferredSize() { //sets size of cell
return new Dimension(75, 75);
}
}
}

Related

Changing colors of smaller JPanels in a pane

I am having a problem with using MouseListener in order to change the color of a panel, which is among many other similar panels in rows and columns. This is my progress so far:
import java.awt.*;
import javax.swing.*;
import java.awt.Color.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.util.Random;
public class Checkers extends JFrame implements MouseListener
{
Random random = new Random();
private final int ROWS = 2;
private final int COLS = 5;
private final int GAP = 2;
private final int NUM = ROWS * COLS;
private int x;
private JPanel pane = new JPanel(new GridLayout(ROWS,COLS, GAP,GAP));
private JPanel pane2 = new JPanel();
private JPanel [] panel = new JPanel[NUM];
private Color col1 = Color.RED;
private Color col2 = Color.WHITE;
private Color tempColor;
public Checkers()
{
super("Checkers");
setSize(600,600);
setVisible(true);
addMouseListener(this);
mouseClicked(null);
setBackground(Color.BLACK);
setBoard();
}
public void setBoard()
// rotates colors on the checkbaord
{
for(int x = 0; x < NUM; x++) {
panel[x] = new JPanel();
pane.add(panel[x]);
if (x % COLS == 0) {
tempColor = col1;
col1 = col2;
col2 = tempColor;}
if (x % 2 == 0) {
panel[x].setBackground(col1);}
else {
panel[x].setBackground(col2);}
}
//pane background colour and the size of this pane.
pane.setBackground(Color.BLACK);
pane.setPreferredSize(new Dimension(300,300));
//pane background colour and size of this pane.
pane2.setBackground(Color.BLACK);
pane2.setPreferredSize(new Dimension(300,300));
//directions on the board where these panes appear.
add(pane, BorderLayout.WEST);
add(pane2, BorderLayout.EAST);
pane2.setLayout(new BoxLayout(pane2, BoxLayout.PAGE_AXIS));
}
#Override
public void mouseClicked(MouseEvent arg0) {
//randomly generate a new color for one of the panes when that pane is clicked.
int r = random.nextInt(255);
int g = random.nextInt(255);
int b = random.nextInt(255);
setBackground(new Color(r, g, b));
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
Expected result - What I'd like to do with this is once one of the red or white panels are clicked, it triggers the mouseClicked override and sets the colour of that panel to black (currently set to a random rgb, but doesn't work anyway), so the user knows this has been pressed. The rest of the overrides are left empty as they serve no purpose to me at this moment.
Current result - The program executes, but the pane colors don't change once clicked.
Here is the direct image file of what the program looks like when currently executed:
Any help is welcome.
There might be better ways to do what you want, but one way is to create a custom JPanel class:
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;
public class MyPanel extends JPanel implements MouseListener {
public MyPanel() {
addMouseListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
setBackground(Color.BLACK);
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
Then instead of creating an array of regular JPanels:
private JPanel[] panel = new JPanel[NUM];
You can create an array of the custom JPanels:
private MyPanel[] panel = new MyPanel[NUM];
The custom JPanels all have their own MouseListeners so when one is clicked, it updates itself.

How to add Player to Maze

I have constructed a maze and made a player class. When I compile it, I only see the maze and not the player. I have tried different techniques and still it doesn't work for me.
What exactly do I have to do in order to see the player and be able to move it?
Also, is there a way to adjust the maze and make it bigger or same size as frame?
import java.awt.*;
import javax.swing.*;
import java.awt.event.*; // Needed for ActionListener
import javax.swing.event.*; // Needed for ActionListener
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
class www extends JFrame
{
static Maze maze = new Maze ();
static Timer t;
//======================================================== constructor
public www ()
{
// 1... Create/initialize components
// 2... Create content pane, set layout
JPanel content = new JPanel (); // Create a content pane
content.setLayout (new BorderLayout ()); // Use BorderLayout for panel
JPanel north = new JPanel ();
north.setLayout (new FlowLayout ()); // Use FlowLayout for input area
DrawArea board = new DrawArea (500, 500);
// 3... Add the components to the input area.
content.add (north, "North"); // Input area
content.add (board, "South"); // Output area
// 4... Set this window's attributes.
setContentPane (content);
pack ();
setTitle ("MAZE");
setSize (490, 500);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo (null); // Center window.
}
public static void main (String[] args)
{
www window = new www ();
window.setVisible (true);
player p = new player ();
JFrame jf = new JFrame ();
//jf.setTitle("Tutorial");
//jf.setSize(600,400);
jf.setVisible(true);
}
class DrawArea extends JPanel
{
public DrawArea (int width, int height)
{
this.setPreferredSize (new Dimension (width, height)); // size
}
public void paintComponent (Graphics g)
{
maze.show (g); // display current state of colony
}
}
}
class Maze
{
private int grid [][];
public Maze ()
{
int [][] maze =
{ {1,0,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,1,0,1,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,1,1,1,0,1},
{1,0,0,0,1,1,1,0,0,0,0,0,1},
{1,0,1,0,0,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,0,0,1},
{1,0,1,0,1,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,0,1},
{1,1,1,1,1,1,1,1,1,1,1,0,1}};
grid = maze;
}
public void show (Graphics g)
{
for (int row = 0 ; row < grid.length ; row++)
for (int col = 0 ; col < grid [0].length ; col++)
{
if (grid [row] [col] == 1) // life
g.setColor (Color.black);
else
g.setColor (Color.white);
g.fillRect (col * 30 + 30, row * 30 + 30, 30, 30); // draw life form
}
}
public class player extends JPanel implements ActionListener,KeyListener
{
Timer tm = new Timer(5,this);
private int x = 0;
private int y = 0;
private int velX = 0 ;
private int velY = 0;
public void player ()
{
tm.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(20,30,50,50);
}
public void actionPerformed(ActionEvent e)
{
x = x+velX;
y = y +velY;
repaint();
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
if(c == KeyEvent.VK_LEFT)
{
velX = -1;
velY = 0;
}
if (c == KeyEvent.VK_UP)
{
velX = 0;
velY = -1;
}
if( c==KeyEvent.VK_RIGHT)
{
velX = 1;
velY = 0;
}
if(c==KeyEvent.VK_DOWN)
{
velX = 0;
velY = 1;
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e){}
}
}

I need a little help implementing player movement on java grid

I need a little help with java, I am new to the language hence I have no idea on how to implement such.
I have already made a basic 15;40 grid JLabel Image, thanks to this site as well, what I need help with is about how to make a player(Supposed to be an Image, also shown on the grid) move around using either WASD(I don't know if Ascii-approach works on java) or Arrow Keys.
Here's my code for the Grid
public class GUI {
static Scanner cns = new Scanner(System.in);
JFrame frame = new JFrame();
ImageIcon ImageIcon = new ImageIcon("Grass.png");
JLabel[][] grid;
public GUI(int width, int length) {
Container pane = frame.getContentPane();
frame.setLayout(new GridLayout(width,length));
grid = new JLabel[width][length];
for(int y = 0; y < length; y++) {
for(int x = 0; x < width; x++) {
grid[x][y] = new JLabel();
grid[x][y].setBorder(BorderFactory.createLineBorder(Color.black));
grid[x][y].setBorder(BorderFactory.createEmptyBorder());
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
for(int y = 0; y < length; y++) {
for(int x = 0; x < width; x++) {
pane.add(grid[x][y]= new JLabel(new ImageIcon("Grass.png")));
grid[x][y].setBorder(BorderFactory.createLineBorder(Color.black));
grid[x][y].setBorder(BorderFactory.createEmptyBorder());
frame.add(grid[x][y]);
}
}
}
public static void main(String[] args) {
new GUI(15, 40);
}
}
Couple of suggestions here:
1 - Make GUI extend JFrame and implement KeyListener.
You have to override KeyListener methods (keyPressed, keyReleased, and keyTyped) and you should override repaint() from JFrame.
The repaint method should call super.repaint() at the end to update frames.
2 - Have the fields of GUI store data about the things that need to be drawn.
You probably should store the grid, or what's in the grid as fields.
3 - The constructor should initialize, not render.
Rendering should be done in repaint(). The constructor should do something like this:
super();
JPanel frame = new JPanel();
add(frame);
pack();
addKeyListener(this);
repaint();
This answer is kinda unfinished but I'll look more into it and update this. Particularly, the JPanel is an element in the JFrame.
UPDATE: Here is a small working example. Use WASD to move the rectangle around the screen.
This is the JFrame.
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class MyJFrame extends JFrame implements KeyListener {
private MyJPanel frame;
public MyJFrame() {
super();
frame = new MyJPanel();
add(frame);
pack();
addKeyListener(this);
repaint();
}
public static void main(String[] args) {
MyJFrame window = new MyJFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.setTitle("Test");
}
#Override
public void repaint() {
super.repaint();
}
#Override
public void keyPressed(KeyEvent e) {
frame.keyPressed(e);
repaint();
}
#Override
public void keyTyped(KeyEvent e) { }
#Override
public void keyReleased(KeyEvent e) { }
}
This is the JPanel.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;
public class MyJPanel extends JPanel {
private int x = 0;
private int y = 0;
public MyJPanel() {
setPreferredSize(new Dimension(200,200));
}
#Override
public void update(Graphics g) {
paint(g);
}
#Override
public void paint(Graphics g) {
g.setColor(Color.red);
g.drawRect(x,y,20,20);
}
public void keyPressed(KeyEvent e) {
int k = e.getKeyCode();
switch (k) {
case KeyEvent.VK_D:
x++;
break;
case KeyEvent.VK_A:
x--;
break;
case KeyEvent.VK_W:
y--;
break;
case KeyEvent.VK_S:
y++;
break;
}
}
}
Good luck!

Can't set maximum size of connect 4 grid in Java swing

Right now I am trying to make it so that the connect 4 grid on the gui is always a 7x8 no matter what window size. I have been trying to set the button array with a setMaximumSize and it's not working.
Here is the code that sets the JButton array
void ResetGame()
{
JLabel label = new JLabel("Click a column to drop piece");
for(int r=0;r<gameBoard.length;r++)
{
java.util.Arrays.fill(gameBoard[r],0,gameBoard[r].length,'0');
//loop through board columns
for(int c=0;c<gameBoard[r].length;c++)
{
gameButtons[r][c]= new JButton(empty);
panel.add(gameButtons[r][c]);
gameButtons[r][c].setPreferredSize(new Dimension(70,70));
//Allows buttons to be arranged as grid.
GridLayout grid = new GridLayout(0,8);
//Sets into grid.
gameButtons[r][c].setLayout(grid);
gameButtons[r][c].setMaximumSize(new Dimension(0,10));
}
panel.add(label);
}
// loop through array setting char array back to ' ' and buttons array back to empty pic
// reset currentPlayer and numMoves variables
}
Just in case I'll also include the window creation method here.
public void CreateWindow()
{
//Sets window title and create window object.
JFrame aWindow = new JFrame("Connect Four");
//Set window position and size
aWindow.setBounds(200,100,600,800);
//What close button does.
aWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Make window visible.
aWindow.setVisible(true);
//Sets content area to work with stuff.
aWindow.setContentPane(panel);
//Gets content pane.
Container content = aWindow.getContentPane();
}
Not sure of what you are trying to achieve with setMaximumSize. Without explicit and precise requirements, we can hardly help you.
So, I would suggest that you take a look at the following snippet (which is an SSCCE) and try to find out what you are doing wrong:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Connect4 {
public class GameButton extends JPanel {
private final int row;
private final int column;
private Color color;
public GameButton(final int row, final int column) {
super();
this.row = row;
this.column = column;
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Game button " + row + " " + column + " has been pressed");
}
});
}
public void setColor(Color color) {
this.color = color;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int size = Math.min(getWidth(), getHeight());
int offset = (int) ((double) size / 10);
size = size - 2 * offset;
if (color == null) {
g.setColor(Color.BLACK);
g.drawOval(offset, offset, size, size);
} else {
g.setColor(color);
g.fillOval(offset, offset, size, size);
}
}
}
protected void initUI() {
JPanel gridPanel = new JPanel(new GridLayout(7, 8));
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 8; j++) {
GameButton gameButton = new GameButton(i, j);
gridPanel.add(gameButton);
}
}
JFrame frame = new JFrame(Connect4.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(gridPanel);
frame.setSize(600, 600);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Connect4().initUI();
}
});
}
}
setMaximumSize() puts a bound on how large something can be. Depending on what you are using for a layout manager you want either setPreferredSize() or setSize().

dragging a jlabel around the screen

So I am trying to click and drag a JLabel around a JFrame. The following code allows a JLabel to be moved around the screen when the mouse is pressed / dragged at any point on the screen, but I am not sure how to add a second ActionListener to check if the mouse is clicking on the label, assuming that is the solution.
I would like to have multiple JLabels on the screen so that the only label being moved is the one that the mouse has clicked and is now dragging.
Thanks.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class test extends JFrame implements MouseMotionListener {
private JPanel panel = new JPanel(null);
private JLabel dragLabel = new JLabel("drag test");
private int mouseX = 200;
private int mouseY = 200;
public test() {
this.add(panel);
panel.setBackground(Color.WHITE);
panel.add(dragLabel);
dragLabel.setForeground(Color.RED);
dragLabel.setBounds(mouseX, mouseY, 100, 50);
panel.addMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
dragLabel.setBounds(mouseX, mouseY, 100, 50);
}
#Override
public void mouseMoved(MouseEvent e) {}
public static void main(String[] args) {
test frame = new test();
frame.setVisible(true);
frame.setSize(600, 400);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Another way to do this is to add the JLabel to a JLayeredPane or to a JPanel held by a JLayeredPane and add a MouseAdapter as the JLayeredPane's MouseListener and MouseMotionListener. Then when clicking on the label, move it to the JLayeredPane's JLayeredPane.DRAG_LAYER so it moves on top of everything else, then place the JLabel on whichever is the most appropriate level on mouse release. I've found this to work well when moving chess pieces on a chess board, for instance, and you want to make sure that the piece you're moving is displayed above all the other pieces when dragging.
Addition: You've probably left this thread, but if you come back, or for the benefit of others, I wanted to clarify what I meant by using a JLayeredPane by posting an example.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DragLabelOnLayeredPane extends JLayeredPane {
public static final int WIDTH = 680;
public static final int HEIGHT = 480;
private static final int GRID_ROWS = 8;
private static final int GRID_COLS = 6;
private static final int GAP = 3;
private static final Dimension LAYERED_PANE_SIZE = new Dimension(WIDTH, HEIGHT);
private static final Dimension LABEL_SIZE = new Dimension(60, 40);
private GridLayout gridlayout = new GridLayout(GRID_ROWS, GRID_COLS, GAP, GAP);
private JPanel backingPanel = new JPanel(gridlayout);
private JPanel[][] panelGrid = new JPanel[GRID_ROWS][GRID_COLS];
private JLabel redLabel = new JLabel("Red", SwingConstants.CENTER);
private JLabel blueLabel = new JLabel("Blue", SwingConstants.CENTER);
public DragLabelOnLayeredPane() {
backingPanel.setSize(LAYERED_PANE_SIZE);
backingPanel.setLocation(2 * GAP, 2 * GAP);
backingPanel.setBackground(Color.black);
for (int row = 0; row < GRID_ROWS; row++) {
for (int col = 0; col < GRID_COLS; col++) {
panelGrid[row][col] = new JPanel(new GridBagLayout());
backingPanel.add(panelGrid[row][col]);
}
}
redLabel.setOpaque(true);
redLabel.setBackground(Color.red.brighter().brighter());
redLabel.setPreferredSize(LABEL_SIZE);
panelGrid[4][3].add(redLabel);
blueLabel.setOpaque(true);
blueLabel.setBackground(Color.blue.brighter().brighter());
blueLabel.setPreferredSize(LABEL_SIZE);
panelGrid[1][1].add(blueLabel);
backingPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setPreferredSize(LAYERED_PANE_SIZE);
add(backingPanel, JLayeredPane.DEFAULT_LAYER);
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
private class MyMouseAdapter extends MouseAdapter {
private JLabel dragLabel = null;
private int dragLabelWidthDiv2;
private int dragLabelHeightDiv2;
private JPanel clickedPanel = null;
#Override
public void mousePressed(MouseEvent me) {
clickedPanel = (JPanel) backingPanel.getComponentAt(me.getPoint());
Component[] components = clickedPanel.getComponents();
if (components.length == 0) {
return;
}
// if we click on jpanel that holds a jlabel
if (components[0] instanceof JLabel) {
// remove label from panel
dragLabel = (JLabel) components[0];
clickedPanel.remove(dragLabel);
clickedPanel.revalidate();
clickedPanel.repaint();
dragLabelWidthDiv2 = dragLabel.getWidth() / 2;
dragLabelHeightDiv2 = dragLabel.getHeight() / 2;
int x = me.getPoint().x - dragLabelWidthDiv2;
int y = me.getPoint().y - dragLabelHeightDiv2;
dragLabel.setLocation(x, y);
add(dragLabel, JLayeredPane.DRAG_LAYER);
repaint();
}
}
#Override
public void mouseDragged(MouseEvent me) {
if (dragLabel == null) {
return;
}
int x = me.getPoint().x - dragLabelWidthDiv2;
int y = me.getPoint().y - dragLabelHeightDiv2;
dragLabel.setLocation(x, y);
repaint();
}
#Override
public void mouseReleased(MouseEvent me) {
if (dragLabel == null) {
return;
}
remove(dragLabel); // remove dragLabel for drag layer of JLayeredPane
JPanel droppedPanel = (JPanel) backingPanel.getComponentAt(me.getPoint());
if (droppedPanel == null) {
// if off the grid, return label to home
clickedPanel.add(dragLabel);
clickedPanel.revalidate();
} else {
int r = -1;
int c = -1;
searchPanelGrid: for (int row = 0; row < panelGrid.length; row++) {
for (int col = 0; col < panelGrid[row].length; col++) {
if (panelGrid[row][col] == droppedPanel) {
r = row;
c = col;
break searchPanelGrid;
}
}
}
if (r == -1 || c == -1) {
// if off the grid, return label to home
clickedPanel.add(dragLabel);
clickedPanel.revalidate();
} else {
droppedPanel.add(dragLabel);
droppedPanel.revalidate();
}
}
repaint();
dragLabel = null;
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("DragLabelOnLayeredPane");
frame.getContentPane().add(new DragLabelOnLayeredPane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
Please feel free to post any questions, need for clarification, or corrections.
Inspired by your code and user compilex's answer, follows demonstration:
Full code:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
/**
* A demonstration of moving around labels in a panel.
* <p>
* Some labels show up layed out in a grid. Then the
* user can drag any label anywhere on the panel.
* </p>
*/
public class LabelDragger {
public static void main(final String[] args) {
final int labelRows = 5, //How many rows of labels.
labelColumns = 5, //How many columns of labels.
labelWidth = 55, //Width for each label.
labelHeight = 20; //Height for each label.
//Border colors for labels:
final Color[] colors = new Color[]{Color.BLUE, Color.GREEN, Color.BLACK, Color.GRAY};
final Random prng = new Random(); //For selecting border color for each label.
final JPanel dragP = new JPanel(null); //Nicely set to null! :D Did not know that trick.
//Creating the listener for the panel:
final MouseAdapter ma = new MouseAdapter() {
private JLabel selectedLabel = null; //Clicked label.
private Point selectedLabelLocation = null; //Location of label in panel when it was clicked.
private Point panelClickPoint = null; //Panel's click point.
//Selection of label occurs upon pressing on the panel:
#Override
public void mousePressed(final MouseEvent e) {
//Find which label is at the press point:
final Component pressedComp = dragP.findComponentAt(e.getX(), e.getY());
//If a label is pressed, store it as selected:
if (pressedComp != null && pressedComp instanceof JLabel) {
selectedLabel = (JLabel) pressedComp;
selectedLabelLocation = selectedLabel.getLocation();
panelClickPoint = e.getPoint();
//Added the following 2 lines in order to make selectedLabel
//paint over all others while it is pressed and dragged:
dragP.setComponentZOrder(selectedLabel, 0);
selectedLabel.repaint();
}
else {
selectedLabel = null;
selectedLabelLocation = null;
panelClickPoint = null;
}
}
//Moving of selected label occurs upon dragging in the panel:
#Override
public void mouseDragged(final MouseEvent e) {
if (selectedLabel != null
&& selectedLabelLocation != null
&& panelClickPoint != null) {
final Point newPanelClickPoint = e.getPoint();
//The new location is the press-location plus the length of the drag for each axis:
final int newX = selectedLabelLocation.x + (newPanelClickPoint.x - panelClickPoint.x),
newY = selectedLabelLocation.y + (newPanelClickPoint.y - panelClickPoint.y);
selectedLabel.setLocation(newX, newY);
}
}
};
dragP.addMouseMotionListener(ma); //For mouseDragged().
dragP.addMouseListener(ma); //For mousePressed().
//Filling the panel with labels:
for (int row = 0; row < labelRows; ++row)
for (int col = 0; col < labelColumns; ++col) {
//Create label for (row, col):
final JLabel lbl = new JLabel("Label" + (row * labelColumns + col));
lbl.setHorizontalAlignment(JLabel.CENTER);
//lbl.setVerticalAlignment(JLabel.CENTER);
lbl.setBounds(col * labelWidth, row * labelHeight, labelWidth, labelHeight); //Grid-like positioning.
lbl.setBorder(new LineBorder(colors[prng.nextInt(colors.length)], 2)); //Set a border for clarity.
//Add label to panel:
dragP.add(lbl);
}
//Creating and showing the main frame:
final JFrame frame = new JFrame(LabelDragger.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//The size of the content pane adds some extra room for moving the labels:
final Dimension paneSize = new Dimension((int)(1.5 * labelWidth * labelColumns),
(int)(1.5 * labelHeight * labelRows));
frame.getContentPane().setPreferredSize(paneSize);
frame.getContentPane().add(dragP);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Explanations are added as comments.
Tips:
Take a look at the documentation on Container.findComponentAt(int x, int y), if you are going to add Components on the dragP Container, other than "draggable" labels.
Also, you can instead use Container.getComponentAt(int x, int y), in this case. I suggest you read their (small) documentation first.
Add a mouse listener to the label instead of the panel. (You might still need a mouse listener on the panel for the dragging but at least the one on the label can tell you if it was selected).
Create two global variables:
int x_pressed = 0;
int y_pressed = 0;
then create two events (mousePressed and mouseDragged over JLabel):
lbl_banner.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e) {
//catching the current values for x,y coordinates on screen
x_pressed = e.getX();
y_pressed = e.getY();
}
});
lbl_banner.addMouseMotionListener(new MouseMotionAdapter(){
#Override
public void mouseDragged(MouseEvent e){
//and when the Jlabel is dragged
setLocation(e.getXOnScreen() - x_pressed, e.getYOnScreen() - y_pressed);
}
});

Categories