如何使 Jpanel 的所有区域都可拖动,包括其中的 JSVGCanvas
How to make all of the region of a Jpanel draggable including a JSVGCanvas within it
我一直在遵循本指南
http://softwareisart.blogspot.co.uk/2011/11/drag-and-drop-of-complex-custom-objects.html
使我的自定义 Jpanel 可拖动(通过拖动手势),但由于某些原因,只有没有组件的 JPanel 区域是可拖动的。我有一个 JSVGCanvas(来自 batik 库),里面有一些绘画,然后我将其添加到我的自定义 JPanel 中。
过去为了使 JPanel 上的悬停事件突出显示,我会执行以下操作以将鼠标悬停事件从 canvas 传递到外部 jpanel 来解决此问题。
@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);}
但是我不确定如何将拖动事件从 canvas 传递到持有 canvas 的 jpanel。
有什么方法可以将 canvas 绑定到 JPanel,这样当我单击 JPanel 中的任何位置时,它会通过 canvas 到达 JPanel?
谢谢
更新
嗨,理查德。使用 JLayer 似乎不错,因为它现在包含 JSVGCanvas 和持有 canvas 的 JPanel。但是我应该如何在 "drag gesture processing here" 位中添加拖动手势。我通常会如下向我的 JPanel 添加一个拖动事件。
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);'
还有我的拖动手势
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
而MyDropTargetListImp是这样的。
class MyDropTargetListImp 扩展了 DropTargetAdapter 实现
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
错误:(281, 21) java:不兼容的类型:java.awt.AWTEvent 无法转换为 java.awt.dnd.MouseDragGestureRecognizer
最终更新
JLayers 帮了我一点忙,但我最终通过以下方式实现了它。
在 Richard 编写的 JLayer class 中,我只是向 canvas 和 JLayer 添加了一个 gestureListener,并为每个将 JLayer 传递给 cavas 的实现创建了单独的 GesturesImplementations。
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;
阿里
在 Java 7 或更高版本中,您应该能够将 JPanel 包装在 JLayer 实例中,该实例拦截当前进入 JSVGCanvas 的鼠标事件。这将允许您在包装器中进行拖动手势处理。
下面是 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();
}
});
}
}
我一直在遵循本指南 http://softwareisart.blogspot.co.uk/2011/11/drag-and-drop-of-complex-custom-objects.html
使我的自定义 Jpanel 可拖动(通过拖动手势),但由于某些原因,只有没有组件的 JPanel 区域是可拖动的。我有一个 JSVGCanvas(来自 batik 库),里面有一些绘画,然后我将其添加到我的自定义 JPanel 中。
过去为了使 JPanel 上的悬停事件突出显示,我会执行以下操作以将鼠标悬停事件从 canvas 传递到外部 jpanel 来解决此问题。
@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);}
但是我不确定如何将拖动事件从 canvas 传递到持有 canvas 的 jpanel。
有什么方法可以将 canvas 绑定到 JPanel,这样当我单击 JPanel 中的任何位置时,它会通过 canvas 到达 JPanel?
谢谢
更新
嗨,理查德。使用 JLayer 似乎不错,因为它现在包含 JSVGCanvas 和持有 canvas 的 JPanel。但是我应该如何在 "drag gesture processing here" 位中添加拖动手势。我通常会如下向我的 JPanel 添加一个拖动事件。
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);'
还有我的拖动手势
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
而MyDropTargetListImp是这样的。 class MyDropTargetListImp 扩展了 DropTargetAdapter 实现 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
错误:(281, 21) java:不兼容的类型:java.awt.AWTEvent 无法转换为 java.awt.dnd.MouseDragGestureRecognizer
最终更新
JLayers 帮了我一点忙,但我最终通过以下方式实现了它。 在 Richard 编写的 JLayer class 中,我只是向 canvas 和 JLayer 添加了一个 gestureListener,并为每个将 JLayer 传递给 cavas 的实现创建了单独的 GesturesImplementations。
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;
阿里
在 Java 7 或更高版本中,您应该能够将 JPanel 包装在 JLayer 实例中,该实例拦截当前进入 JSVGCanvas 的鼠标事件。这将允许您在包装器中进行拖动手势处理。
下面是 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();
}
});
}
}