Need Help With D&D Program
Hi, I'm not sure if I'm allowed to post questions on this forum but I can't find anywhere to talk to helpful people about programming.
I'm making a dnd interface for JComponents. So far I've made a simple program that has a Component that can be lifted from a container and braught to the glass pane then later moved to anywhere on the screen and dropped into the container below it. Here's where my problems come:
1) Rite now my 'Movable Component' is a JPanel which is just colored in. I want to either take a Graphic2d from a JComponent/Component and draw it on the JPanel or change the JPanel to the component I want to paint and disable the component.
The problem with getting the Graphics2d is that if the component isn't on the screen it doesn't make a graphic object. I tried messing with the ui delicate and overriding parental methods for paintComponent, repaint, and that repaintChildren(forget name) but I haven't had luck getting a good graphics object. I was thinking of, at the beginning of running the program, putting 1 of each component onto the screen for a second then removing it but I'd rather not. I'd also like to change the graphics dynamicly if someone stretches the component there dropping and what not.
The problem with disabling is that it changes some of the visual features of Components. I want to be able to update the Component myself to change how it looks and I don't want disabling to gray out components.
I mainly just dont want the components to do any of there normal fuctions. This is for a page builder, by the way.
Another problem I'm having is that mouseMotionListener is allowing me to select 2 components that are on top of one another when there edges are near each other. I don't know if theres a fix to this other than changing the Java Class.
My next problem is a drop layout manager, but I'm doing pretty good with that rite now. It'll problem just move components out of the way of the falling component.
One last thing I need help with is that I don't want the object that's being carried to go across the menu bar and certain areas. When I'm having the object being carried I have it braught up to the glass pane which allows it to move anywhere. Does anyone have any idea how I could prevent the component from being over the menu bars and other objects? I might have to make 1 panel is the movable area that can then be broken down into the 'component bank', 'building page' and whatever else I'm gonna need.
This is all just test code to get together for when I make the real program but I need to make sure it'll be possible without a lot of hacking of code.
Sorry for the length. Thanks for any help you can give.
[2767 byte] By [
E-Rocka] at [2007-10-3 3:04:06]

The trick to making viewable components that have no behaviour, is to render them onto an image of some sort (eg a BufferedImage). You can then display the Image on a JLabel that can be dragged around the desktop.
Here is a piece of code that does the component rendering for you. This particular example uses a fixed component size, but you can modify that as you choose of course...public class JComponentImage
{
private static GraphicsConfiguration gConfig;
private static Dimension compSize = new Dimension(80, 22);
private static Image image = null;
public static Image getImage(Class objectClass)
{
if (gConfig == null)
{
GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gDevice = gEnv.getDefaultScreenDevice();
gConfig = gDevice.getDefaultConfiguration();
}
image = gConfig.createCompatibleImage(compSize.width, compSize.height);
JComponent jc = (JComponent) ObjectFactory.instantiate(objectClass);
jc.setSize(compSize);
Graphics g = image.getGraphics();
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, compSize.width, compSize.height);
g.setColor(Color.BLACK);
jc.paint(g);
return image;
}
}
And here is the class that makes the dragable JLabel using the class above...public class Dragable extends JLabel
{
private static DragSource dragSource = DragSource.getDefaultDragSource();
private static DragGestureListener dgl = new DragMoveGestureListener();
private static TransferHandler th = new ObjectTransferHandler();
private Class compClass;
private Image image;
Dragable(Class compClass)
{
this.compClass = compClass;
image = JComponentImage.getImage(compClass);
setIcon(new ImageIcon(image));
setTransferHandler(th);
dragSource.createDefaultDragGestureRecognizer(this,
DnDConstants.ACTION_COPY,
dgl);
}
public Class getCompClass()
{
return compClass;
}
}
Oh and here is ObjectFactory which simply instantiates Objects of a given class and sets their text to their classname (very crudely)...public class ObjectFactory
{
public static Object instantiate(Class objectClass)
{
Object o = null;
try
{
o = objectClass.newInstance();
}
catch (Exception e)
{
System.out.println("ObjectFactory#instantiate: " + e);
}
String name = objectClass.getName();
int lastDot = name.lastIndexOf('.');
name = name.substring(lastDot + 1);
if (o instanceof JLabel)
((JLabel)o).setText(name);
if (o instanceof JButton)
((JButton)o).setText(name);
if (o instanceof JTextComponent)
((JTextComponent)o).setText(name);
return o;
}
}
Two more classes required by this codepublic class ObjectTransferHandler extends TransferHandler {
private static DataFlavor df;
/**
* Constructor for ObjectTransferHandler.
*/
public ObjectTransferHandler() {
super();
try {
df = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType);
} catch (ClassNotFoundException e) {
Debug.trace(e.toString());
}
}
public Transferable createTransferable(JComponent jC) {
Transferable t = null;
try {
t = new ObjectTransferable(((Dragable) jC).getCompClass());
} catch (Exception e) {
Debug.trace(e.toString());
}
return t;
}
public int getSourceActions(JComponent c) {
return DnDConstants.ACTION_MOVE;
}
public boolean canImport(JComponent comp, DataFlavor[] flavors) {
if (!(comp instanceof Dragable) && flavors[0].equals(df))
return true;
return false;
}
public boolean importData(JComponent comp, Transferable t) {
JComponent c = null;
try {
c = (JComponent) t.getTransferData(df);
} catch (Exception e) {
Debug.trace(e.toString());
}
comp.add(c);
comp.validate();
return true;
}
}
public class ObjectTransferable implements Transferable {
private static DataFlavor df = null;
private Class objectClass;
ObjectTransferable(Class objectClass) {
try {
df = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType);
} catch (ClassNotFoundException e) {
System.out.println("ObjectTransferable: " + e);
}
this.objectClass = objectClass;
}
/**
* @see java.awt.datatransfer.Transferable#getTransferDataFlavors()
*/
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { df };
}
/**
* @see java.awt.datatransfer.Transferable#isDataFlavorSupported(DataFlavor)
*/
public boolean isDataFlavorSupported(DataFlavor testDF) {
return testDF.equals(df);
}
/**
* @see java.awt.datatransfer.Transferable#getTransferData(DataFlavor)
*/
public Object getTransferData(DataFlavor arg0)
throws UnsupportedFlavorException, IOException {
return ObjectFactory.instantiate(objectClass);
}
}
And of course the test class:public class DragAndDropTest extends JFrame
{
JPanel leftPanel = new JPanel();
JPanel rightPanel = new JPanel();
Container contentPane = getContentPane();
Dragable dragableJLabel;
Dragable dragableJButton;
Dragable dragableJTextField;
Dragable dragableJTextArea;
/**
* Constructor DragAndDropTest.
* @param title
*/
public DragAndDropTest(String title)
{
super(title);
dragableJLabel = new Dragable(JLabel.class);
dragableJButton = new Dragable(JButton.class);
dragableJTextField = new Dragable(JTextField.class);
dragableJTextArea = new Dragable(JTextArea.class);
leftPanel.setBorder(new EtchedBorder());
BoxLayout boxLay = new BoxLayout(leftPanel, BoxLayout.Y_AXIS);
leftPanel.setLayout(boxLay);
leftPanel.add(dragableJLabel);
leftPanel.add(dragableJButton);
leftPanel.add(dragableJTextField);
leftPanel.add(dragableJTextArea);
rightPanel.setPreferredSize(new Dimension(500,500));
rightPanel.setBorder(new EtchedBorder());
rightPanel.setTransferHandler(new ObjectTransferHandler());
contentPane.setLayout(new BorderLayout());
contentPane.add(leftPanel, "West");
contentPane.add(rightPanel, "Center");
}
public static void main(String[] args)
{
JFrame frame = new DragAndDropTest("Drag and Drop Test");
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
I wrote this code some time ago, so it won't be perfect but hopefully will give you some good ideas.
Regards,
Tim