如何使 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();
            }
        });
    }
}