13 Replies - 9412 Views - Last Post: 30 September 2009 - 09:30 AM Rate Topic: -----

#1 konos5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 32
  • Joined: 09-September 09

Moving JLabels across JPanels using the JLayeredPane...

Post icon  Posted 09 September 2009 - 03:03 PM

Hello everyone,

I found this piece of code in SUN's forums, dated back to 2007 and posted by a user named "camickr"
It's actually about a little chessboard...Just copy and compile in your favourite editor...(->Just don't forget to replace the 2 images<-)

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();
		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.red : Color.white );
			else
				square.setBackground( i % 2 == 0 ? Color.white : Color.red );
		}
 
		// Add a few pieces to the board
 
		JLabel piece = new JLabel( new ImageIcon("dukewavered.gif") );
		JPanel panel = (JPanel)chessBoard.getComponent( 0 );
		panel.add( piece );
		piece = new JLabel( new ImageIcon("dukewavered.gif") );
		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);
		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 );
		}
 
		chessPiece.setVisible(true);
	}
 
	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.pack();
		frame.setResizable( false );
		frame.setLocationRelativeTo( null );
		frame.setVisible(true);
	 }
}


After looking at the code I can say that I pretty much figured it out.
Apart from one thing. Try doing the following and you will immediately notice a very weird
program behaviour which I believe "hides" a lot:

1)Cross out the "chessPiece=null" under the mousePressed event
2)Recomplile and run the app
3)Drag the little picture that is placed over the first square to another -empty- square (a random one - doesn't really matter)
4)Now, click on a -blank- square and try to drag it like there was your picture on it. You will notice that while you are dragging "nothing", your picture
will disappear and will only reappear once you release the mouse button, right over where you did it.

Why is this thing happening? - I mean now that the "chessPiece" won't be getting "nulled" anymore, its status must be permanently changed to JLabel and its position to the DRAG_LAYER. Why is it getting disappeared when dragged though?

P.S. I have also noticed one more thing...
Try clicking and dragging the chess piece to the second diagonal red square in the top left corner. Now click in the third diagonal, and drag the mouse up to the top left corner. As you reach the top left square, the chess piece will be start being drawn back in the second diagonal square.

I have no explanation over this behaviour and up to now I haven't the slightest clue of why is that happening.
Please notify me for any further clarifications.

Thank you in advance for your time.

Is This A Good Question/Topic? 0
  • +

Replies To: Moving JLabels across JPanels using the JLayeredPane...

#2 konos5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 32
  • Joined: 09-September 09

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 10 September 2009 - 10:29 AM

Please...anyone?
Was This Post Helpful? 0
  • +
  • -

#3 konos5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 32
  • Joined: 09-September 09

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 19 September 2009 - 11:30 AM

Please....you are my only hope...
I can't seem to find an answer nowhere...
Was This Post Helpful? 0
  • +
  • -

#4 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8327
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 19 September 2009 - 12:52 PM

View Postkonos5, on 9 Sep, 2009 - 02:03 PM, said:

After looking at the code I can say that I pretty much figured it out.
Apart from one thing. Try doing the following and you will immediately notice a very weird
program behaviour which I believe "hides" a lot:

1)Cross out the "chessPiece=null" under the mousePressed event
2)Recomplile and run the app
3)Drag the little picture that is placed over the first square to another -empty- square (a random one - doesn't really matter)
4)Now, click on a -blank- square and try to drag it like there was your picture on it. You will notice that while you are dragging "nothing", your picture
will disappear and will only reappear once you release the mouse button, right over where you did it.

Why is this thing happening? - I mean now that the "chessPiece" won't be getting "nulled" anymore, its status must be permanently changed to JLabel and its position to the DRAG_LAYER. Why is it getting disappeared when dragged though?

P.S. I have also noticed one more thing...
Try clicking and dragging the chess piece to the second diagonal red square in the top left corner. Now click in the third diagonal, and drag the mouse up to the top left corner. As you reach the top left square, the chess piece will be start being drawn back in the second diagonal square.

I have no explanation over this behaviour and up to now I haven't the slightest clue of why is that happening.
Please notify me for any further clarifications.

Thank you in advance for your time.

That is why he set chessPiece to null so it won't be dragged here
	public void mouseDragged(MouseEvent me)
	{
		if (chessPiece == null) return;


if you had clicked on the JPanel (and not a piece of chess) here
	public void mousePressed(MouseEvent e)
	{
		chessPiece = null;
		Component c =  chessBoard.findComponentAt(e.getX(), e.getY());

		if (c instanceof JPanel) return;



could have been coded that way

   public void mousePressed(MouseEvent e)
	{
		Component c =  chessBoard.findComponentAt(e.getX(), e.getY());

		if (c instanceof JPanel) {
			pieceSelected = false;
			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);
		pieceSelected = true;
	}

	/*
	**  Move the chess piece around
	*/
	public void mouseDragged(MouseEvent me)
	{
		if (!pieceSelected) return;

		chessPiece.setLocation(me.getX() + xAdjustment, me.getY() + yAdjustment);
	 }

	/*
	**  Drop the chess piece back onto the chess board
	*/
	public void mouseReleased(MouseEvent e)
	{
		if (!pieceSelected) return;

		chessPiece.setVisible(false);
		Component c =  chessBoard.findComponentAt(e.getX(), e.getY());



This post has been edited by pbl: 19 September 2009 - 01:10 PM

Was This Post Helpful? 0
  • +
  • -

#5 konos5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 32
  • Joined: 09-September 09

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 19 September 2009 - 03:07 PM

First of all, thank you very much for answering my post.

What you actually did was improving my original code and making it "cleaner".
I appreciate your code which by the way, eliminates completely all the problems.

BUT IF WE USE THE ORIGINAL CODE, we will inevitably run into the problem I describe.

So, if we comment out the "chessPiece=null;" line under the mousePressed event, then the behaviour of the app becomes mostly weird.

Again, do the following:

1)Launch the app.
2)Try "drag 'n' dropping" normally the first time
3)Then try to drag an empty panel. You will now notice that the "chessPiece" field (that would be the image) won't be following your mouse as it was supposed to be due to the setLocation method under the mouseDragged event...

Sorry if all of this is a bit vague...please let me know if you need any further clarifications...

This post has been edited by konos5: 19 September 2009 - 03:08 PM

Was This Post Helpful? 0
  • +
  • -

#6 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8327
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 19 September 2009 - 03:57 PM

Why would you want to comment that line ?

I explaines to you what this line does... and so why it shouldn't be commented out !!! What else do you want ?

If you cut & paste code from the internet and don't understand it why would you want to touch hit ?

This line makes it work... without that line it wont work !!! (for the reasons explained)
What this line did to you that you absolutly want to comment it ?

Sure if you comment a line that shouldn't be you can expect strange behaviours

Quote

Again, do the following:

1)Launch the app.
2)Try "drag 'n' dropping" normally the first time
3)Then try to drag an empty panel. You will now notice that the "chessPiece" field (that would be the image) won't be following your mouse as it was supposed to be due to the setLocation method under the mouseDragged event...

Why should I try to run an application where I have commented a line of code ?
The application works as it is

class MyClass {
	public static void main(String[] args) {
	  System.out.println("Hello world");
   }
}



Try this application
if you comment the line: System.out.println("Hello world");
it does not display "Hello world" anymore
why ?

We are in an ackward situation
You downloaded code from the Internet that WORKS
now you ask us: "Why does that code does not work if I comment line N" ?

This post has been edited by pbl: 19 September 2009 - 04:04 PM

Was This Post Helpful? 0
  • +
  • -

#7 konos5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 32
  • Joined: 09-September 09

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 19 September 2009 - 04:39 PM

I'll tell you what...

Initially I commented out this line by mistake. When I did figure out why my app wouldn't work correctly, I simply put the line back and eveything returned to normal...

But then I started thinking about the changes this line was doing to the app...
AND the problem is that these changes ---whether the app was now working correctly or not,--- didn't make sense...

To conclude, I don't care if the app works correctly or not. If I need my app to work flawlessly then I 'll simply keep the original code. BUT what I do care about is what happens "under the hood" while having this particular line commented out...

All of the above have nothing to do with projects or courseworks.
They are all just for my personal education.

Thanks again.

This post has been edited by konos5: 19 September 2009 - 04:42 PM

Was This Post Helpful? 0
  • +
  • -

#8 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8327
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 19 September 2009 - 06:11 PM

So ?

You insisted twice:

Quote

Please...anyone?


then

Quote

Please....you are my only hope...
I can't seem to find an answer nowhere...


So I spent time to find out why commenting out a line of code (of an application you haven't written) make the application NOT to work...
I explained to you what this line was doing and why it was important

and you come back telling me:

"And commenting out this line ALSO disturb the application there and there" ya and ? Told you it was important so: just don't comment it out !!!
What else do you want ? Expect ?

This post has been edited by pbl: 19 September 2009 - 06:41 PM

Was This Post Helpful? 0
  • +
  • -

#9 konos5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 32
  • Joined: 09-September 09

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 19 September 2009 - 08:05 PM

You spent your time reading through my code and I am very grateful for it and I thank you for that.

But the thing is that you only told me that this line is important for the program to work and then you suggested me a new and cleaner way of making this app work BETTER...
--I do understand why the app doesn't work CORRECTLY with the particular line commented out.

What I don't understand are the resulting "side effects" of this line commented out.

---I am expecting an answer on why when dragging an empty panel, the chessPiece image won't follow the mouse. (given that we've done a proper drag n drop at least once)---
The chessPiece field will already be stored as a JLabel component and must be following the mouse despite that the mousePressed event was called over an empty panel. The mouseDragged event has already the order: whatever is stored at the chessPiece field, and whenever that was stored, just make it follow the mouse...
How do you explain that it doesn't?

---I am also expecting an answer on that:

Quote

Try clicking and dragging the chessPiece to the second diagonal red square in the top left corner. Now click in the third diagonal, and drag the mouse up to the top left corner. As you reach the top left square, the chess piece will be start being drawn back in the second diagonal square.


I think I am quite clear and have made my point this time around.
Was This Post Helpful? 0
  • +
  • -

#10 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8327
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 19 September 2009 - 08:27 PM

View Postkonos5, on 19 Sep, 2009 - 07:05 PM, said:

You spent your time reading through my code and I am very grateful for it and I thank you for that.

First we will both agree that this NOT YOUR code
I am really happy to help people fixing code THEY wrote but here you are stucked with code you cut & pasted

View Postkonos5, on 19 Sep, 2009 - 07:05 PM, said:

But the thing is that you only told me that this line is important for the program to work and then you suggested me a new and cleaner way of making this app work BETTER...
--I do understand why the app doesn't work CORRECTLY with the particular line commented out.

so rewrite the whole thing if you are not happy with the way it behaves

Quote

What I don't understand are the resulting "side effects" of this line commented out.

It is because you damage the whole thing... you shoudn't be able to drag the chess piece if you click on an empty cell
that is why the origonal author set to null the checkPiece if a click happened on the JPanel (not the best way to do it but it works)

Quote

---I am expecting an answer on why when dragging an empty panel, the chessPiece image won't follow the mouse. (given that we've done a proper drag n drop at least once)---

The original author manage so that you can't drag an empty panel... you defeat that purpose by commenting the line that was taking care of that

Quote

The chessPiece field will already be stored as a JLabel component and must be following the mouse despite that the mousePressed event was called over an empty panel. The mouseDragged event has already the order: whatever is stored at the chessPiece field, and whenever that was stored, just make it follow the mouse...
How do you explain that it doesn't?


That is what you wish but it hasn't been design that way... write your own and stop asking us questions on something you haven't written
You are starting to abuse my patience

Quote

---I am also expecting an answer on that:
Try clicking and dragging the chessPiece to the second diagonal red square in the top left corner. Now click in the third diagonal, and drag the mouse up to the top left corner. As you reach the top left square, the chess piece will be start being drawn back in the second diagonal square.


Ya, you broke the whole thing by commenting out the line that set the chessPiece to null
Was This Post Helpful? 0
  • +
  • -

#11 konos5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 32
  • Joined: 09-September 09

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 20 September 2009 - 08:29 AM

Quote

First we will both agree that this NOT YOUR code
I am really happy to help people fixing code THEY wrote but here you are stucked with code you cut & pasted


Exactly.
I am telling you that I can't understand how a piece of code works and you worry about the "intellectual properties"?? What difference does it make?
It's a snippet that I can't understand. Doesn't matter who wrote it.
Of course it wasn't me. "my code" was referring to the code that I posted and not wrote by myself.
Is there a rule in this forum forbitting to post code that you didn't write by yourself??
And just for the record, I contacted the original author of the code(in SUN's forums)

link: http://forums.sun.co...hreadID=5405895

asking the exact same question and he told me that he had no clue why after commenting that line out. That's why I came to this forum claiming that you are my only hope on understanding this one.


Good or Bad tactic I commented that line out. What causes that behaviour is still unknown.

Anyway, thanks for everything.
Fairwell.

This post has been edited by konos5: 20 September 2009 - 10:09 AM

Was This Post Helpful? 0
  • +
  • -

#12 konos5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 32
  • Joined: 09-September 09

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 26 September 2009 - 08:50 AM

Do you know where can I find the JLayeredPane.java source code?
Was This Post Helpful? 0
  • +
  • -

#13 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8327
  • View blog
  • Posts: 31,857
  • Joined: 06-March 08

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 26 September 2009 - 10:34 AM

View Postkonos5, on 26 Sep, 2009 - 07:50 AM, said:

Do you know where can I find the JLayeredPane.java source code?

/javax/swing/JLayeredPane.java

/*
 * @(#)JLayeredPane.java	1.54 04/05/05
 *
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package javax.swing;

import java.awt.Component;
import java.util.ArrayList;
import java.util.Hashtable;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;

import javax.accessibility.*;

/**
 * <code>JLayeredPane</code> adds depth to a JFC/Swing container,
 * allowing components to overlap each other when needed.
 * An <code>Integer</code> object specifies each component's depth in the
 * container, where higher-numbered components sit &quot;on top&quot; of other 
 * components.
 * For task-oriented documentation and examples of using layered panes see
 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/layeredpane.html">How to Use a Layered Pane</a>,
 * a section in <em>The Java Tutorial</em>.
 * <P>
 * <TABLE ALIGN="RIGHT" BORDER="0" SUMMARY="layout">
 * <TR>
 *   <TD ALIGN="CENTER">
 *	 <P ALIGN="CENTER"><IMG SRC="doc-files/JLayeredPane-1.gif" 
 *	 alt="The following text describes this image."
 *	 WIDTH="269" HEIGHT="264" ALIGN="BOTTOM" BORDER="0">
 *   </TD>
 * </TR>
 * </TABLE>
 * For convenience, <code>JLayeredPane</code> divides the depth-range
 * into several different layers. Putting a component into one of those
 * layers makes it easy to ensure that components overlap properly,
 * without having to worry about specifying numbers for specific depths:
 * <DL>
 *	<DT><FONT SIZE="2">DEFAULT_LAYER</FONT></DT>
 *		 <DD>The standard layer, where most components go. This the bottommost 
 *		 layer.
 *	<DT><FONT SIZE="2">PALETTE_LAYER</FONT></DT>
 *		 <DD>The palette layer sits over the default layer. Useful for floating 
 *		 toolbars and palettes, so they can be positioned above other components.
 *	<DT><FONT SIZE="2">MODAL_LAYER</FONT></DT>
 *		 <DD>The layer used for modal dialogs. They will appear on top of any
 *		 toolbars, palettes, or standard components in the container.
 *	<DT><FONT SIZE="2">POPUP_LAYER</FONT></DT>
 *		 <DD>The popup layer displays above dialogs. That way, the popup windows 
 *		 associated with combo boxes, tooltips, and other help text will appear 
 *		 above the component, palette, or dialog that generated them.
 *	<DT><FONT SIZE="2">DRAG_LAYER</FONT></DT>
 *		 <DD>When dragging a component, reassigning it to the drag layer ensures 
 *		 that it is positioned over every other component in the container. When 
 *		 finished dragging, it can be reassigned to its normal layer.
 * </DL>
 * The <code>JLayeredPane</code> methods <code>moveToFront(Component)</code>, 
 * <code>moveToBack(Component)</code> and <code>setPosition</code> can be used 
 * to reposition a component within its layer. The <code>setLayer</code> method 
 * can also be used to change the component's current layer.
 *
 * <h2>Details</h2>
 * <code>JLayeredPane</code> manages its list of children like
 * <code>Container</code>, but allows for the definition of a several
 * layers within itself. Children in the same layer are managed exactly
 * like the normal <code>Container</code> object,
 * with the added feature that when children components overlap, children 
 * in higher layers display above the children in lower layers.
 * <p>  
 * Each layer is a distinct integer number. The layer attribute can be set 
 * on a <code>Component</code> by passing an <code>Integer</code>
 * object during the add call.<br> For example:
 * <PRE>
 *	 layeredPane.add(child, JLayeredPane.DEFAULT_LAYER);
 * or
 *	 layeredPane.add(child, new Integer(10));
 * </PRE>
 * The layer attribute can also be set on a Component by calling<PRE>
 *	 layeredPaneParent.setLayer(child, 10)</PRE>
 * on the <code>JLayeredPane</code> that is the parent of component. The layer
 * should be set <i>before</i> adding the child to the parent.
 * <p>
 * Higher number layers display above lower number layers. So, using 
 * numbers for the layers and letters for individual components, a
 * representative list order would look like this:<PRE>
 *	   5a, 5b, 5c, 2a, 2b, 2c, 1a </PRE>
 * where the leftmost components are closest to the top of the display.
 * <p>
 * A component can be moved to the top or bottom position within its
 * layer by calling <code>moveToFront</code> or <code>moveToBack</code>.
 * <p>
 * The position of a component within a layer can also be specified directly.
 * Valid positions range from 0 up to one less than the number of 
 * components in that layer. A value of -1 indicates the bottommost
 * position. A value of 0 indicates the topmost position. Unlike layer
 * numbers, higher position values are <i>lower</i> in the display.
 * <blockquote> 
 * <b>Note:</b> This sequence (defined by java.awt.Container) is the reverse 
 * of the layer numbering sequence. Usually though, you will use <code>moveToFront</code>,
 * <code>moveToBack</code>, and <code>setLayer</code>.
 * </blockquote>
 * Here are some examples using the method add(Component, layer, position):
 * Calling add(5x, 5, -1) results in:<PRE>
 *	   5a, 5b, 5c, 5x, 2a, 2b, 2c, 1a </PRE>
 *
 * Calling add(5z, 5, 2) results in:<PRE>
 *	   5a, 5b, 5z, 5c, 5x, 2a, 2b, 2c, 1a </PRE>
 *
 * Calling add(3a, 3, 7) results in:<PRE>
 *	   5a, 5b, 5z, 5c, 5x, 3a, 2a, 2b, 2c, 1a </PRE>
 *
 * Using normal paint/event mechanics results in 1a appearing at the bottom
 * and 5a being above all other components.
 * <p>
 * <b>Note:</b> that these layers are simply a logical construct and LayoutManagers
 * will affect all child components of this container without regard for
 * layer settings.
 * <p>
 * <strong>Warning:</strong>
 * Serialized objects of this class will not be compatible with
 * future Swing releases. The current serialization support is
 * appropriate for short term storage or RMI between applications running
 * the same version of Swing.  As of 1.4, support for long term storage
 * of all JavaBeans<sup><font size="-2">TM</font></sup>
 * has been added to the <code>java.beans</code> package.
 * Please see {@link java.beans.XMLEncoder}.
 * 
 * @version 1.36 02/02/00
 * @author David Kloba
 */
public class JLayeredPane extends JComponent implements Accessible {
	/// Watch the values in getObjectForLayer()
	/** Convenience object defining the Default layer. Equivalent to new Integer(0).*/
	public final static Integer DEFAULT_LAYER = new Integer(0);
	/** Convenience object defining the Palette layer. Equivalent to new Integer(100).*/
	public final static Integer PALETTE_LAYER = new Integer(100);
	/** Convenience object defining the Modal layer. Equivalent to new Integer(200).*/
	public final static Integer MODAL_LAYER = new Integer(200);
	/** Convenience object defining the Popup layer. Equivalent to new Integer(300).*/
	public final static Integer POPUP_LAYER = new Integer(300);
	/** Convenience object defining the Drag layer. Equivalent to new Integer(400).*/
	public final static Integer DRAG_LAYER = new Integer(400);
	/** Convenience object defining the Frame Content layer. 
	  * This layer is normally only use to positon the contentPane and menuBar 
	  * components of JFrame.
	  * Equivalent to new Integer(-30000).
	  * @see JFrame
	  */
	public final static Integer FRAME_CONTENT_LAYER = new Integer(-30000);

	/** Bound property */
	public final static String LAYER_PROPERTY = "layeredContainerLayer";
	// Hashtable to store layer values for non-JComponent components
	private Hashtable<Component,Integer> componentToLayer;
	private boolean optimizedDrawingPossible = true;


//////////////////////////////////////////////////////////////////////////////
//// Container Override methods 
//////////////////////////////////////////////////////////////////////////////
	/** Create a new JLayeredPane */
	public JLayeredPane() {
		setLayout(null);
	}

	private void validateOptimizedDrawing() {
		boolean layeredComponentFound = false;
		synchronized(getTreeLock()) {
			Integer layer = null;

			for (Component c : getComponents()) {
				layer = null;
				if(c instanceof JInternalFrame || (c instanceof JComponent &&
						 (layer = (Integer)((JComponent)c).getClientProperty(
						  LAYER_PROPERTY)) != null)) {
					if(layer != null && layer.equals(FRAME_CONTENT_LAYER))
						continue;
					layeredComponentFound = true;
					break;
				}
			}
		}
		
		if(layeredComponentFound)
			optimizedDrawingPossible = false;
		else
			optimizedDrawingPossible = true;
	}
	
	protected void addImpl(Component comp, Object constraints, int index) {
		int layer = DEFAULT_LAYER.intValue();
		int pos;

		if(constraints instanceof Integer) {
			layer = ((Integer)constraints).intValue();
			setLayer(comp, layer);
		} else
			layer = getLayer(comp);

		pos = insertIndexForLayer(layer, index);
		super.addImpl(comp, constraints, pos);
		comp.validate();
		comp.repaint();
		validateOptimizedDrawing();
	}

	/**
	 * Remove the indexed component from this pane.
	 * This is the absolute index, ignoring layers. 
	 *
	 * @param index  an int specifying the component to remove
	 * @see #getIndexOf
	 */
	public void remove(int index) {
		Component c = getComponent(index);
		super.remove(index);
		if (c != null && !(c instanceof JComponent)) {
			getComponentToLayer().remove(c);
		}
		validateOptimizedDrawing();
	}

	/** 
	 * Removes all the components from this container.
	 *
	 * @since 1.5
	 */
	public void removeAll() {
		Component[] children = getComponents();
		Hashtable cToL = getComponentToLayer();
		for (int counter = children.length - 1; counter >= 0; counter--) {
			Component c = children[counter];
			if (c != null && !(c instanceof JComponent)) {
				cToL.remove(c);
			}
		}
		super.removeAll();
	}

	/**
	 * Returns false if components in the pane can overlap, which makes
	 * optimized drawing impossible. Otherwise, returns true.
	 *
	 * @return false if components can overlap, else true
	 * @see JComponent#isOptimizedDrawingEnabled
	 */
	public boolean isOptimizedDrawingEnabled() {
		return optimizedDrawingPossible;
	}


//////////////////////////////////////////////////////////////////////////////
//// New methods for managing layers
//////////////////////////////////////////////////////////////////////////////
	/** Sets the layer property on a JComponent. This method does not cause
	  * any side effects like setLayer() (painting, add/remove, etc).
	  * Normally you should use the instance method setLayer(), in order to
	  * get the desired side-effects (like repainting).
	  * 
	  * @param c	  the JComponent to move
	  * @param layer  an int specifying the layer to move it to
	  * @see #setLayer
	  */
	public static void putLayer(JComponent c, int layer) {
		/// MAKE SURE THIS AND setLayer(Component c, int layer, int position)  are SYNCED
		Integer layerObj;

		layerObj = new Integer(layer);
		c.putClientProperty(LAYER_PROPERTY, layerObj);
	}

	/** Gets the layer property for a JComponent, it
	  * does not cause any side effects like setLayer(). (painting, add/remove, etc)
	  * Normally you should use the instance method getLayer().
	  * 
	  * @param c  the JComponent to check
	  * @return   an int specifying the component's layer
	  */
	public static int getLayer(JComponent c) {
		Integer i;
		if((i = (Integer)c.getClientProperty(LAYER_PROPERTY)) != null)
			return i.intValue();
		return DEFAULT_LAYER.intValue();
	}

	/** Convenience method that returns the first JLayeredPane which
	  * contains the specified component. Note that all JFrames have a 
	  * JLayeredPane at their root, so any component in a JFrame will
	  * have a JLayeredPane parent.
	  *
	  * @param c the Component to check
	  * @return the JLayeredPane that contains the component, or
	  *		 null if no JLayeredPane is found in the component
	  *		 hierarchy
	  * @see JFrame
	  * @see JRootPane
	  */
	public static JLayeredPane getLayeredPaneAbove(Component c) {
		if(c == null) return null;
		
		Component parent = c.getParent();
		while(parent != null && !(parent instanceof JLayeredPane))
			parent = parent.getParent();
		return (JLayeredPane)parent;
	}

	/** Sets the layer attribute on the specified component,
	  * making it the bottommost component in that layer.
	  * Should be called before adding to parent. 
	  * 
	  * @param c	 the Component to set the layer for
	  * @param layer an int specifying the layer to set, where 
	  *			  lower numbers are closer to the bottom
	  */
	public void setLayer(Component c, int layer)  {
		setLayer(c, layer, -1);
	}

	/** Sets the layer attribute for the specified component and
	  * also sets its position within that layer.
	  * 
	  * @param c		 the Component to set the layer for
	  * @param layer	 an int specifying the layer to set, where 
	  *				  lower numbers are closer to the bottom
	  * @param position  an int specifying the position within the
	  *				  layer, where 0 is the topmost position and -1
	  *				  is the bottommost position
	  */
	public void setLayer(Component c, int layer, int position)  {
		Integer layerObj;
		layerObj = getObjectForLayer(layer);

		if(layer == getLayer(c) && position == getPosition(c)) {
				repaint(c.getBounds());
			return;
		}
		
		/// MAKE SURE THIS AND putLayer(JComponent c, int layer) are SYNCED
		if(c instanceof JComponent)
			((JComponent)c).putClientProperty(LAYER_PROPERTY, layerObj);
		else
			getComponentToLayer().put((Component)c, layerObj);
		
		if(c.getParent() == null || c.getParent() != this) {
			repaint(c.getBounds());
			return;
		}

		int index = insertIndexForLayer(c, layer, position);

		setComponentZOrder(c, index);
		repaint(c.getBounds());
	}

	/** 
	 * Returns the layer attribute for the specified Component.
	 * 
	 * @param c  the Component to check
	 * @return an int specifying the component's current layer
	 */
	public int getLayer(Component c) {
		Integer i;
		if(c instanceof JComponent)
			i = (Integer)((JComponent)c).getClientProperty(LAYER_PROPERTY);
		else
			i = (Integer)getComponentToLayer().get((Component)c);

		if(i == null)
			return DEFAULT_LAYER.intValue();
		return i.intValue();
	}

	/** 
	 * Returns the index of the specified Component. 
	 * This is the absolute index, ignoring layers.
	 * Index numbers, like position numbers, have the topmost component
	 * at index zero. Larger numbers are closer to the bottom.
	 * 
	 * @param c  the Component to check
	 * @return an int specifying the component's index 
	 */
	public int getIndexOf(Component c) {
		int i, count;
		
		count = getComponentCount();	
		for(i = 0; i < count; i++) {
			if(c == getComponent(i))
				return i;
		}
		return -1;
	}
	/** 
	 * Moves the component to the top of the components in its current layer
	 * (position 0).
	 *
	 * @param c the Component to move 
	 * @see #setPosition(Component, int) 
	 */
	public void moveToFront(Component c) {
		setPosition(c, 0);
	}

	/** 
	 * Moves the component to the bottom of the components in its current layer
	 * (position -1).
	 *
	 * @param c the Component to move 
	 * @see #setPosition(Component, int) 
	 */
	public void moveToBack(Component c) {
		setPosition(c, -1);
	}

	/**
	 * Moves the component to <code>position</code> within its current layer,
	 * where 0 is the topmost position within the layer and -1 is the bottommost
	 * position. 
	 * <p>
	 * <b>Note:</b> Position numbering is defined by java.awt.Container, and
	 * is the opposite of layer numbering. Lower position numbers are closer
	 * to the top (0 is topmost), and higher position numbers are closer to
	 * the bottom.
	 *
	 * @param c		 the Component to move
	 * @param position  an int in the range -1..N-1, where N is the number of
	 *				  components in the component's current layer
	 */
	public void setPosition(Component c, int position) {
		setLayer(c, getLayer(c), position);
	}

	/**
	 * Get the relative position of the component within its layer.
	 *
	 * @param c  the Component to check
	 * @return an int giving the component's position, where 0 is the
	 *		 topmost position and the highest index value = the count
	 *		 count of components at that layer, minus 1
	 *
	 * @see #getComponentCountInLayer
	 */
	public int getPosition(Component c) {
		int i, count, startLayer, curLayer, startLocation, pos = 0;
		
		count = getComponentCount();
		startLocation = getIndexOf(c);

		if(startLocation == -1)
			return -1;
		
		startLayer = getLayer(c);
		for(i = startLocation - 1; i >= 0; i--) {
			curLayer = getLayer(getComponent(i));			   
			if(curLayer == startLayer)
				pos++;
			else
				return pos;
		}
		return pos;
	}

	/** Returns the highest layer value from all current children.
	  * Returns 0 if there are no children.
	  *
	  * @return an int indicating the layer of the topmost component in the 
	  *		 pane, or zero if there are no children
	  */
	public int highestLayer() {
		if(getComponentCount() > 0)
			return getLayer(getComponent(0));		   
		return 0;
	}

	/** Returns the lowest layer value from all current children.
	  * Returns 0 if there are no children.
	  *
	  * @return an int indicating the layer of the bottommost component in the 
	  *		 pane, or zero if there are no children
	  */
	public int lowestLayer() {
		int count = getComponentCount();
		if(count > 0)
			return getLayer(getComponent(count-1));			 
		return 0;
	}

	/**
	 * Returns the number of children currently in the specified layer.
	 *
	 * @param layer  an int specifying the layer to check
	 * @return an int specifying the number of components in that layer
	 */
	public int getComponentCountInLayer(int layer) {
		int i, count, curLayer;
		int layerCount = 0;
		
		count = getComponentCount();
		for(i = 0; i < count; i++) {
			curLayer = getLayer(getComponent(i));			   
			if(curLayer == layer) {
				layerCount++;
			/// Short circut the counting when we have them all
			} else if(layerCount > 0 || curLayer < layer) {
				break;
			}
		}
		
		return layerCount;
	}

	/**
	 * Returns an array of the components in the specified layer.
	 *
	 * @param layer  an int specifying the layer to check
	 * @return an array of Components contained in that layer
	 */
	public Component[] getComponentsInLayer(int layer) {
		int i, count, curLayer;
		int layerCount = 0;
		Component[] results;
		
		results = new Component[getComponentCountInLayer(layer)];
		count = getComponentCount();
		for(i = 0; i < count; i++) {
			curLayer = getLayer(getComponent(i));			   
			if(curLayer == layer) {
				results[layerCount++] = getComponent(i);
			/// Short circut the counting when we have them all
			} else if(layerCount > 0 || curLayer < layer) {
				break;
			}
		}
		
		return results;
	}

	/**
	 * Paints this JLayeredPane within the specified graphics context.
	 *
	 * @param g  the Graphics context within which to paint
	 */
	public void paint(Graphics g) {
		if(isOpaque()) {
			Rectangle r = g.getClipBounds();
			Color c = getBackground();
			if(c == null)
				c = Color.lightGray;
			g.setColor(c);
			if (r != null) {
				g.fillRect(r.x, r.y, r.width, r.height);
			}
			else {
				g.fillRect(0, 0, getWidth(), getHeight());
			}
		}
		super.paint(g);
	}

//////////////////////////////////////////////////////////////////////////////
//// Implementation Details
//////////////////////////////////////////////////////////////////////////////

	/**
	 * Returns the hashtable that maps components to layers.
	 *
	 * @return the Hashtable used to map components to their layers
	 */
	protected Hashtable<Component,Integer> getComponentToLayer() {
		if(componentToLayer == null)
			componentToLayer = new Hashtable<Component,Integer>(4);
		return componentToLayer;
	}
	
	/**
	 * Returns the Integer object associated with a specified layer.
	 *
	 * @param layer an int specifying the layer
	 * @return an Integer object for that layer
	 */
	protected Integer getObjectForLayer(int layer) {
		Integer layerObj;
		switch(layer) {
		case 0:
			layerObj = DEFAULT_LAYER;
			break;
		case 100:
			layerObj = PALETTE_LAYER;
			break;
		case 200:
			layerObj = MODAL_LAYER;
			break;
		case 300:
			layerObj = POPUP_LAYER;
			break;
		case 400:
			layerObj = DRAG_LAYER;
			break;
		default:
			layerObj = new Integer(layer);
		}
		return layerObj;
	}

	/** 
	 * Primitive method that determines the proper location to
	 * insert a new child based on layer and position requests.
	 * 
	 * @param layer	 an int specifying the layer
	 * @param position  an int specifying the position within the layer
	 * @return an int giving the (absolute) insertion-index
	 *
	 * @see #getIndexOf
	 */
	protected int insertIndexForLayer(int layer, int position) {
		return insertIndexForLayer(null, layer, position);
	}

	/** 
	 * This method is an extended version of insertIndexForLayer()
	 * to support setLayer which uses Container.setZOrder which does
	 * not remove the component from the containment heirarchy though
	 * we need to ignore it when calculating the insertion index.
	 * 
	 * @param comp	  component to ignore when determining index
	 * @param layer	 an int specifying the layer
	 * @param position  an int specifying the position within the layer
	 * @return an int giving the (absolute) insertion-index
	 *
	 * @see #getIndexOf
	 */
	private int insertIndexForLayer(Component comp, int layer, int position) {
		int i, count, curLayer;
		int layerStart = -1;
		int layerEnd = -1;
		int componentCount = getComponentCount();
		
		ArrayList<Component> compList =
			new ArrayList<Component>(componentCount);
		for (int index = 0; index < componentCount; index++) {
			if (getComponent(index) != comp) {
				compList.add(getComponent(index));
			}
		}

		count = compList.size();
		for (i = 0; i < count; i++) {
			curLayer = getLayer(compList.get(i));			   
			if (layerStart == -1 && curLayer == layer) {
				layerStart = i;
			}   
			if (curLayer < layer) {
				if (i == 0) { 
					// layer is greater than any current layer  
					// [ ASSERT(layer > highestLayer()) ] 
					layerStart = 0;
					layerEnd = 0;
				} else {
					layerEnd = i;
				}
				break;
			}
		}

		// layer requested is lower than any current layer
		// [ ASSERT(layer < lowestLayer()) ] 
		// put it on the bottom of the stack
		if (layerStart == -1 && layerEnd == -1)
			return count;

		// In the case of a single layer entry handle the degenerative cases
		if (layerStart != -1 && layerEnd == -1)
			layerEnd = count;
		
		if (layerEnd != -1 && layerStart == -1)
			layerStart = layerEnd;
		
		// If we are adding to the bottom, return the last element
		if (position == -1)
			return layerEnd;
		
		// Otherwise make sure the requested position falls in the 
		// proper range
		if (position > -1 && layerStart + position <= layerEnd)
			return layerStart + position;
		
		// Otherwise return the end of the layer
		return layerEnd;
	}

	/**
	 * Returns a string representation of this JLayeredPane. This method 
	 * is intended to be used only for debugging purposes, and the 
	 * content and format of the returned string may vary between	  
	 * implementations. The returned string may be empty but may not 
	 * be <code>null</code>.
	 * 
	 * @return  a string representation of this JLayeredPane.
	 */
	protected String paramString() {
		String optimizedDrawingPossibleString = (optimizedDrawingPossible ?
						 "true" : "false");

	return super.paramString() +
		",optimizedDrawingPossible=" + optimizedDrawingPossibleString;
	}

/////////////////
// Accessibility support
////////////////

	/**
	 * Gets the AccessibleContext associated with this JLayeredPane. 
	 * For layered panes, the AccessibleContext takes the form of an 
	 * AccessibleJLayeredPane. 
	 * A new AccessibleJLayeredPane instance is created if necessary.
	 *
	 * @return an AccessibleJLayeredPane that serves as the 
	 *		 AccessibleContext of this JLayeredPane
	 */
	public AccessibleContext getAccessibleContext() {
		if (accessibleContext == null) {
			accessibleContext = new AccessibleJLayeredPane();
		}
		return accessibleContext;
	}

	/**
	 * This class implements accessibility support for the 
	 * <code>JLayeredPane</code> class.  It provides an implementation of the 
	 * Java Accessibility API appropriate to layered pane user-interface 
	 * elements.
	 * <p>
	 * <strong>Warning:</strong>
	 * Serialized objects of this class will not be compatible with
	 * future Swing releases. The current serialization support is
	 * appropriate for short term storage or RMI between applications running
	 * the same version of Swing.  As of 1.4, support for long term storage
	 * of all JavaBeans<sup><font size="-2">TM</font></sup>
	 * has been added to the <code>java.beans</code> package.
	 * Please see {@link java.beans.XMLEncoder}.
	 */
	protected class AccessibleJLayeredPane extends AccessibleJComponent {

		/**
		 * Get the role of this object.
		 *
		 * @return an instance of AccessibleRole describing the role of the 
		 * object
		 * @see AccessibleRole
		 */
		public AccessibleRole getAccessibleRole() {
			return AccessibleRole.LAYERED_PANE;
		}
	}
}




Was This Post Helpful? 0
  • +
  • -

#14 konos5  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 32
  • Joined: 09-September 09

Re: Moving JLabels across JPanels using the JLayeredPane...

Posted 30 September 2009 - 09:30 AM

First of all thank you very much for the source code.

I think I 've found a solution on what's causing the program's behaviour when we comment out the chessPiece=null; line.

Here's the deal:

The code contains these 2 lines:

layeredPane.addMouseListener( this );
layeredPane.addMouseMotionListener( this );

right?

that means that the mouselistener is added to the pane.
Therefore the pane "catches" the mouse events and interferes.

Now, if you look at the code under the mouseReleased event you will also notice this line:

parent.add( chessPiece );

This line means that after our FIRST drag n drop, upon releasing the mouse button, our "chessPiece" will be placed on top of its parent. But in that case its parent is a JPanel(wherever we left it off). And all the JPanels are located on top of the "chessBoard". Therefore the chessPiece, the JPanels and the chessBoard are all located on the default layer of the JLayeredPane.

layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);

Therefore we conclude that the line

parent.add( chessPiece );

"unlinks" in some way the chessPiece form the drag layer of the pane and places it directly on top of a JPanel along with the rest of the components.
---If the chessPiece was located in the drag layer of the pane, then its container would be the whole JFrame. But in that case, where every component is on the same layer, the chessPiece gets hidden behind all the other panels by default.
So what really happens with that line under the mouseDragged event

chessPiece.setLocation(me.getX() + xAdjustment, me.getY() + yAdjustment);

is that it gets "mistranslated". The chessPiece tries to follow the mouse but because of the pane interfering with the coordinates of the mouse, it gets translated relatively to the chessPiece's container.

That's the reason we can't see it following our mouse when trying to drag an empty panel.

Proof of that, is the fact that the chessPiece will start reappearing only if we hover our mouse over the very first JPanel of the chessBoard as that JPanel is the only one that contains coordinates small enough to be translated and fitted in only one JPanel.(the one we last leave off our chessPiece)
Kudos to my friend Giuseppe for pointing that out.

-------------------------------------------------------------------------------------------------------------------

BUT

Now a new question has emerged.

Under the mousePressed event there is a line:

layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);


which places our chesspiece on top of the chessboard making it possible to drag it around.

If we change the location of that line and instead of putting it under the mousePressed event, we place it under the mouseDragged event, then each time we will try dragging the chesspiece, it will be getting disappeared.
Why is that happening?

This post has been edited by konos5: 30 September 2009 - 09:33 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1