Ive been following this guide http://softwareisart.blogspot.co.uk/2011/11/drag-and-drop-of-complex-custom-objects.html
to make my custom Jpanels draggable(via drag gestures) however for some reason only the region of the JPanel with no components is draggable. I have a JSVGCanvas(from the batik library) which has some painting within it which I then added to my custom JPanel.
In the past for hover events on the JPanel to make it highlightable i would do the following to pass mouse hover events from the canvas to the outside jpanel like this to solve this issue.
@Override public void mouseClicked(MouseEvent e){outside.dispatchEvent(e);}
@Override public void mousePressed(MouseEvent e){outside.dispatchEvent(e);}
@Override public void mouseReleased(MouseEvent e){outside.dispatchEvent(e);}
However Im not sure how im going to pass the drag events from the canvas to the jpanel holding the canvas.
Is thier any way i can bind the canvas to the JPanel so that when i click anywhere in the Jpanel it passes through the canvas to the JPanel?
Thanks
UPDATE
Hi Richard. Using a JLayer seems good since it now encompasses the JSVGCanvas and the JPanel holding the canvas. But How am I supposed to add a drag gesture within the "drag gesture processing here" bit. I normally add a drag event to my JPanel as followed.
DragSource ds = new DragSource();
ds.createDefaultDragGestureRecognizer(SecondChoice,
DnDConstants.ACTION_COPY, new DragGestureListImp());
DragSource ds2 = new DragSource();
ds2.createDefaultDragGestureRecognizer(FirstChoice,
DnDConstants.ACTION_COPY, new DragGestureListImp());
new MyDropTargetListImp(FirstChoice);
new MyDropTargetListImp(SecondChoice);'
And my DragGestures
class DragGestureListImp implements DragGestureListener {
@Override
public void dragGestureRecognized(DragGestureEvent event) {
Cursor cursor = null;
CustomJPanel panel= (CustomJPanel) event.getComponent();
if (event.getDragAction() == DnDConstants.ACTION_COPY) {
cursor = DragSource.DefaultCopyDrop;
}
Canvas canvas= panel.getCanvas();
event.startDrag(cursor, new TransferableCanvas(canvas));
}
} //DragGestureListImp
And MyDropTargetListImp is like this. class MyDropTargetListImp extends DropTargetAdapter implements DropTargetListener {
private DropTarget dropTarget;
private CustomJPanel panel;
public MyDropTargetListImp(CustomJPanel panel) {
this.panel = panel;
dropTarget = new DropTarget(panel, DnDConstants.ACTION_COPY, this,
true, null);
}
public void drop(DropTargetDropEvent event) {
try {
System.out.println("dropped Event");
Transferable tr = event.getTransferable();
CustomJPanel an = (CustomJPanel) tr.getTransferData(dataFlavor);
if (event.isDataFlavorSupported(dataFlavor)) {
event.acceptDrop(DnDConstants.ACTION_COPY);
this.panel.updateMyStuff(an)
event.dropComplete(true);
this.panel.validate();
return;
}
event.rejectDrop();
} catch (Exception e) {
e.printStackTrace();
event.rejectDrop();
}
} //drop
} //MyDropTargetListImp
Error:(281, 21) java: incompatible types: java.awt.AWTEvent cannot be converted to java.awt.dnd.MouseDragGestureRecognizer
UPDATE FINAL
The JLayers helped me a little but i finally implemented it by the following. Within the JLayer class that Richard wrote i simply added a gestureListener to both the canvas and the JLayer and created separate GesturesImplementations for each one passing the JLayer to the cavas's implementation.
DragSource ds = new DragSource();
// create a component to be decorated with the layer
// This would be your custom component.
CustomPanel customPanel = new CustomPanel (index, information);
//customPanel.add(new JButton("JButton"));
JLayer tempLayerUI = new JLayer<JComponent>(customPanel, layerUI);
ds.createDefaultDragGestureRecognizer(customPanel.canvas,
DnDConstants.ACTION_COPY, new DragGestureListImp1(tempLayerUI));
ds.createDefaultDragGestureRecognizer(tempLayerUI,
DnDConstants.ACTION_COPY, new DragGestureListImp());
return tempLayerUI;
Ali
In Java 7 or later, you should be able to wrap your JPanel in a JLayer instance that intercepts the mouse events that are currently going to your JSVGCanvas. This will allow you to do the drag gesture processing in the wrapper.
Below is an adapted version of the sample code from https://docs.oracle.com/javase/7/docs/api/javax/swing/JLayer.html
public class JLayerSample {
private static JLayer<JComponent> createLayer() {
// This custom layerUI will intercept all mouseMotion events generated within its borders and delegate to the wrapped JPanel
LayerUI<JComponent> layerUI = new LayerUI<JComponent>() {
public void installUI(JComponent c) {
super.installUI(c);
// enable mouse events for the layer's subcomponents
((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
}
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
// reset the layer event mask
((JLayer) c).setLayerEventMask(0);
}
// overridden method which catches MouseMotion events
public void eventDispatched(AWTEvent e, JLayer<? extends JComponent> l) {
if (e instanceof MouseEvent) {
System.out.println("MouseEvent detected " + e);
// Do drag gesture processing here.
// Note, you cannot dispatch these events to the view component, since that
// creates an event loop.
}
}
};
// create a component to be decorated with the layer
// This would be your custom component.
JPanel panel = new JPanel();
panel.add(new JButton("JButton"));
// create the layer for the panel using our custom layerUI
return new JLayer<JComponent>(panel, layerUI);
}
private static void createAndShowGUI() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// work with the layer as with any other Swing component
frame.add(createLayer());
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}