简体   繁体   English

用Java拖放

[英]Drag and Drop in Java

I have been searching the internet to find examples or how to use java's drag and drop. 我一直在互联网上搜索示例或如何使用Java的拖放功能。 I have found a few, but all the examples only allow you to drag into a specific location, ie another list box or text area. 我发现了一些,但是所有示例仅允许您拖动到特定位置,即另一个列表框或文本区域。 I want to know if there is a way to drag items onto a jpanel or similar container, having the item put anywhere freely on the container. 我想知道是否有一种方法可以将项目拖到jpanel或类似的容器上,让该项目自由地放在容器上的任何位置。

As long as the target is a supported drop target for the item you are dragging then you can drop it to containers like JPanel . 只要目标是要拖动的项目的受支持的放置目标,就可以将其放置到JPanel容器中。

You control the way the dragged item is displayed at the drop location. 您可以控制拖动的项目在放置位置的显示方式。 If your panel overrides paintComponent() then you can paint the item however you find appropriate. 如果您的面板覆盖了paintComponent()则可以绘制项目,但可以找到合适的项目。

'is a way to drag items into a jpanel' '是将项目拖到jpanel中的一种方式'

You can set a DropTarget to your 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 ) {
    }
}

I implemented Drag&Drop in this way: 我以这种方式实现了拖放:

The quite convenient mechanism for the implementation of Drag&Drop has appeared in Java 6, but it does have its disadvantages. Java 6中已经出现了用于拖放操作的非常方便的机制,但是它确实有其缺点。 For example, you should explicitly specify a Drop Target, what is not very useful when you need to lay down the object near the Drop Target. 例如,您应该明确指定放置目标,当您需要将对象放置在放置目标附近时,这不是很有用。 Also in the standard implementation there is no guarantee of execution order of listeners' methods. 同样在标准实现中,不能保证侦听器方法的执行顺序。 I'll tell you the concept of implementing a more extensible Drag&Drop. 我将告诉您实现更可扩展的拖放的概念。

Initially the mouse listeners (Mouse Listener and MouseMotionListener) should be assigned to all Drag Sources. 最初,应将鼠标侦听器(Mouse Listener和MouseMotionListener)分配给所有“拖动源”。 It's need to implement 3 methods: a method of mouse click on the object, a method of moving the mouse while holding the mouse button on the object (mouseDragged in MouseMotionListener) and the mouse up method. 它需要实现3种方法:在对象上单击鼠标的方法,在对象上按住鼠标按钮的同时移动鼠标的方法(MouseMotionListener中的mouseDragged)和鼠标上移方法。

The listeners assignment looks as follows: 侦听器分配如下所示:

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

Accordingly when you click on the object Drag&Drop starts, when you move the mouse the object should be moved, when you release the mouse the object should change its position and be moved to a new container. 因此,当您单击对象时,“拖放”操作开始,当您移动鼠标时,该对象应被移动;当您释放鼠标时,该对象应更改其位置,并被移动到新的容器中。 If the object will be moved in the frame of one container, then it is possible to implement only mouseDragged () method, in which the coordinates of the dragged object will be changed: 如果对象将在一个容器的框架中移动,则可以仅实现mouseDragged()方法,在该方法中将更改被拖动对象的坐标:

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

But dragged object coordinates can be set relative to the container in which it is located. 但是可以相对于其所在的容器设置拖动对象的坐标。 Accordingly, when the mouse is moved to another container it is necessary to add a component to a new container and to calculate the new coordinates, etc. This method is not very beautiful and extensible, so I suggest using GlassPane to display the dragged object. 因此,当鼠标移动到另一个容器时,有必要将组件添加到新容器中并计算新坐标等。此方法不是很漂亮且可扩展,因此我建议使用GlassPane来显示拖动的对象。

The algorithm looks as follows: 该算法如下所示:

  • Click on the object. 单击对象。

  • Get a screenshot of the object (see how to make a screenshot ). 获取对象的屏幕截图(请参阅如何制作屏幕截图 )。 Hide the original object. 隐藏原始对象。

  • Draw on glassPane a screenshot of the object, based on the coordinates of the mouse. 根据鼠标的坐标,在glassPane上绘制对象的屏幕快照。

  • When you move the mouse you need to redraw a screenshot according to the new coordinates. 移动鼠标时,您需要根据新坐标重新绘制屏幕截图。

  • When you release the mouse you need to place the object on the container under which the cursor is located. 释放鼠标时,需要将对象放置在光标所在的容器上。

  • Display the original object. 显示原始对象。

With this approach, we have no any dependences on the container on which the cursor should be placed to make Drop and correspondingly the object can be "Dropped" anywhere. 通过这种方法,我们对放置光标以放置Drop的容器没有任何依赖,并且相应地,该对象可以在任何地方“拖放”。

GlassPane with transparency effect: 具有透明效果的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);

    }
}

In this response only concept of implementation is given. 在该响应中,仅给出了实现的概念。

This information is taken from my article: Frequently Asked Questions during Java applet development 此信息摘自我的文章: Java applet开发期间的常见问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM