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]
# 1
Am I not getting any responses because my post is to long?
E-Rocka at 2007-7-14 20:54:05 > top of Java-index,Desktop,Core GUI APIs...
# 2

When dealing with complex components like this there are a lot of possibilities depending on what you are trying to do.

Does anyone have any idea how I could prevent the component from being over the menu bars and other objects?

If you stick with the glass pane you could define a Rectangle or (aggregate) Area in your mouse event code/class which defines the no_fly_zone space and use it to avoid these areas.

Another possibility is to use a non-opaque top JPanel in an OverlayLayout and have it cover only the components you want to traverse, excluding the JMenuBar and other areas.

1) Rite now my 'Movable Component'...

Copying the graphics does not sound good. When you transfer the JPanel from its place below to the glass pane, why don't you drop it onto the target? What are you trying to do with this transfer? What is the final result you are after?

I mainly just dont want the components to do any of there normal fuctions

?

My next problem is a drop layout manager...

Are you using components on the final component, managing/drawing text, images? Are you using a TransferHandler/DnD architecture or your own event code? Many questions...

mouseMotionListener is allowing me to select 2 components...

You have to decide how you want to deal with these kind of things.

...I need to make sure it'll be possible without a lot of hacking of code.

You may not hit the bulls eye on the first attempt. Think of it as a learning experience and feel your way through. Starting over and redesigning are okay; don't wait.

74philipa at 2007-7-14 20:54:05 > top of Java-index,Desktop,Core GUI APIs...
# 3

Thanks for the response.

Rite now im working on demo code to make sure that each part is possible without making major packages. This one part is a small part of a larger project. I guess I should tell you more about the project so that you can better understand my point of view.

This part of the project is to make a user interface for creating your own gui. The 'User' drag and drops buttons, sliders, button groups, and whatever else is in there 'Component Toolbox', onto a page. Then the 'User' sets parameters for the components. For example a for a slider the range from _ to _ and for button groups how many are selectable, other options could be appearance.

After having a page of setup components the 'User' finalizes the gui and precides to distrubute the forum to people to fill out. The people filling them out run the gui as an actual active page.

E-Rocka at 2007-7-14 20:54:05 > top of Java-index,Desktop,Core GUI APIs...
# 4

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

TimRyanNZa at 2007-7-14 20:54:05 > top of Java-index,Desktop,Core GUI APIs...
# 5
you forgot to post DragMoveGestureListener class codethanks
ghiblina at 2007-7-14 20:54:05 > top of Java-index,Desktop,Core GUI APIs...
# 6
Oops sorry - will try to remember to add it when I'm next at home.
TimRyanNZa at 2007-7-14 20:54:05 > top of Java-index,Desktop,Core GUI APIs...
# 7

Well it is very simple...

import java.awt.dnd.DragGestureEvent;

import java.awt.dnd.DragGestureListener;

import java.awt.event.InputEvent;

import javax.swing.JComponent;

import javax.swing.TransferHandler;

/**

* DragMoveGestureListener is used to recognise a drag initiation event.

* @author Tim Ryan

*/

public class DragMoveGestureListener implements DragGestureListener {

public DragMoveGestureListener() {

super();

}

/**

* @see java.awt.dnd.DragGestureListener#dragGestureRecognized(DragGestureEvent)

*/

public void dragGestureRecognized(DragGestureEvent dge) {

JComponent c = (JComponent) dge.getComponent();

InputEvent event = dge.getTriggerEvent();

c.getTransferHandler().exportAsDrag(c, event, TransferHandler.MOVE);

}

}

TimRyanNZa at 2007-7-14 20:54:05 > top of Java-index,Desktop,Core GUI APIs...
# 8

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);

This doesnt deal with the fact that the ui manager has to do stuff to the JComponent to make the component paint the rite graphics.

I haven't tried your code but I have tried to run paint on a Graphics object and then set the graphics of the label to it.

E-Rocka at 2007-7-14 20:54:05 > top of Java-index,Desktop,Core GUI APIs...
# 9
Why don't you try it. It may do what you want.
TimRyanNZa at 2007-7-14 20:54:05 > top of Java-index,Desktop,Core GUI APIs...