1

我一直在互联网上搜索示例或如何使用 java 的拖放。我找到了一些,但所有的例子都只允许你拖到一个特定的位置,即另一个列表框或文本区域。我想知道是否有办法将项目拖到 jpanel 或类似容器上,让项目自由地放在容器上的任何位置。

4

3 回答 3

2

只要目标是您拖动的项目的受支持放置目标,那么您就可以将其放置到容器中,例如JPanel.

您可以控制拖动项目在放置位置的显示方式。如果您的面板覆盖paintComponent(),那么您可以绘制您认为合适的项目。

于 2013-01-24T11:04:06.103 回答
2

'是一种将项目拖入 jpanel 的方法'

您可以将 DropTarget 设置为您的 JPanel。

public class MyDropTarget extends JPanel implements DropTargetListener {

    private MyImage image;
    private String text;

    public MyDropTarget() {
        setBackground(new Color(30,60,10));
        this.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED, new Color(30,60,10).brighter(), new Color(30,60,10).darker() ) );
        DropTarget dt = new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, this, true, null);
        this.setDropTarget( dt );
    }

    @Override
    public void paintComponent( Graphics g ) {
        super.paintComponent( g );
        if( image != null && image.getImage() != null ) {
            g.drawImage( image.getImage(), 0, 0, null );
            if(image.isError()){
                g.setColor(Color.BLACK);
                g.drawString( text, 0, 0 );
            }
        }
    }

    public void dragEnter( DropTargetDragEvent dtde ) {
        this.setBorder( BorderFactory.createBevelBorder( BevelBorder.RAISED, Color.RED.brighter(), Color.RED.darker() ) );
    }

    public void dragExit( DropTargetEvent dte ) {
        this.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED, UIManager.getColor( "MenuBar.highlight" ), UIManager.getColor( "MenuBar.shadow" ) ) );
    }

    public void dragOver( DropTargetDragEvent dtde ) {
    }

    public void drop( DropTargetDropEvent dtde ) {
        try {           
            text  = (String) dtde.getTransferable().getTransferData( DataFlavor.stringFlavor );
            image = (MyImage)dtde.getTransferable().getTransferData( DataFlavor.imageFlavor );
            this.setBorder( BorderFactory.createBevelBorder( BevelBorder.LOWERED, new Color(30,60,10).brighter(), new Color(30,60,10).darker() ) );
            dtde.dropComplete( true );
            repaint();
        } catch( UnsupportedFlavorException e ) {
            e.printStackTrace();
        } catch( IOException e ) {
            e.printStackTrace();
        } 
        this.setDropTarget( null );
    }

    public void dropActionChanged( DropTargetDragEvent dtde ) {
    }
}
于 2013-01-24T11:04:16.070 回答
1

我以这种方式实现了拖放:

Java 6 中已经出现了非常方便的拖放实现机制,但它确实有其缺点。例如,您应该明确指定放置目标,当您需要在放置目标附近放置对象时,这不是很有用。同样在标准实现中,不能保证侦听器方法的执行顺序。我将告诉您实现更具扩展性的拖放的概念。

最初,鼠标侦听器(Mouse Listener 和 MouseMotionListener)应分配给所有拖动源。它需要实现3个方法:鼠标点击对象的方法、按住鼠标按钮移动鼠标的方法(MouseMotionListener中的mouseDragged)和鼠标向上的方法。

侦听器分配如下所示:

component.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        //block click right mouse button
        if (MouseEvent.BUTTON1 == e.getButton()) {
            startDrag(e);
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        //block click right mouse button
        if (MouseEvent.BUTTON1 == e.getButton()) {
            endDrag(e);
        }
    }
});

component.addMouseMotionListener(new MouseMotionAdapter() {
    @Override
    public void mouseDragged(MouseEvent e) {
        drag(e);
   }
});

因此,当您单击对象拖放开始时,当您移动鼠标时,对象应该被移动,当您释放鼠标时,对象应该改变它的位置并被移动到一个新的容器中。如果要在一个容器的框架内移动对象,则可以只实现 mouseDragged() 方法,在该方法中,被拖动对象的坐标会发生变化:

@Override
public void mouseDragged(MouseEvent e) {
    Point mouseLocation = e.getLocationOnScreen();
    Component draggedComponent = (Component) e.getSource();
    SwingUtilities.convertPointFromScreen(mouseLocation, 
draggedComponent.getParent());
    draggedComponent.setLocation(mouseLocation);
}

但是被拖动对象的坐标可以相对于它所在的容器来设置。因此,当鼠标移动到另一个容器时,需要在新的容器中添加组件,计算新的坐标等。这种方法不是很美观,扩展性也不是很好,所以我建议使用 GlassPane 来显示被拖动的对象。

该算法如下所示:

  • 单击对象。

  • 获取对象的屏幕截图(请参阅如何制作屏幕截图)。隐藏原始对象。

  • 根据鼠标的坐标在 glassPane 上绘制对象的屏幕截图。

  • 当您移动鼠标时,您需要根据新坐标重新绘制屏幕截图。

  • 当您释放鼠标时,您需要将对象放在光标所在的容器上。

  • 显示原始对象。

使用这种方法,我们对放置光标以进行 Drop 的容器没有任何依赖,相应地,对象可以在任何地方“Dropped”。

具有透明效果的 GlassPane:

public class GhostGlassPane extends JPanel {
    private final AlphaComposite composite;
    private BufferedImage ghostImage = null;
    private Point location = new Point(0, 0);

    public GhostGlassPane() {
        setOpaque(false);
        composite = AlphaComposite.getInstance(AlphaComposite.
SRC_OVER, 0.7f);
}
public void paintComponent(Graphics g) {

    if (ghostImage == null)
        return;

    Graphics2D g2 = (Graphics2D) g;
    g2.setComposite(composite);
    g2.drawImage(ghostImage, (int) (location.getX()),
(int) (location.getY()), null);

    }
}

在这个回复中,只给出了实现的概念。

此信息摘自我的文章:Java 小程序开发过程中的常见问题

于 2015-01-06T11:38:47.770 回答