微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Java AWT:如何最好地防止拖动的形状与另一个形状重叠

如何解决Java AWT:如何最好地防止拖动的形状与另一个形状重叠

我是一名经验丰富的 Java 开发人员,但我是用户界面开发的新手,我一直在使用 Java AWT 开发应用程序。我想在用户界面中添加拖动功能

令我惊讶的是,java.awt.Shape 不是 java.awt.Component,因此我没有看到将可拖动钩子添加到我的特定形状的“一流”方式。相反,我利用应用程序窗口的鼠标事件挂钩,然后在处理任何拖动之前简单地检测鼠标光标何时位于感兴趣的形状上。

由于我的应用程序不需要 Z 轴层的复杂性,我限制任何拖动的形状与另一个可拖动的形状相交。如果用户一个拖到另一个上,它只会“碰撞”并保持在那里。然后用户首先将其从碰撞中拖出,然后将其放置在其他地方。您会注意到,在我为 Stackoverflow 留下评论的paint() 方法中检测到了交集。

用户界面有效。除此之外,很容易产生一种竞争条件,如果我非常快速地拖动形状,它可能会深深地嵌套在另一个形状中并卡住。

问题:我是否以完全错误的方式处理这个问题?是否有一种优雅的最佳实践可以在进一步事件发生之前“及时”检测碰撞?

package test;

import java.awt.Basicstroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.ScrollPane;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.RoundRectangle2D;

/**
 * Simple graphical application with two white rectangles that can be dragged around the application window
 * */
final class DraggableTest extends Component implements MouseListener,MouseMotionListener {

    public static void main( String[] args ) {
        
        Frame window = new Frame( "Test Dragging Things" );
        ScrollPane scrollPane = new ScrollPane();
        DraggableTest app = new Draggabletest();
        scrollPane.add( app );
        window.add( scrollPane );
        
        app.setSize( new Dimension( 400,400 ) );
        app.setPreferredSize( new Dimension( 400,400 ) );
        window.setSize( 200,200 );
        window.setVisible( true );

        window.addWindowListener( new WindowAdapter() {
            @Override
            public void windowClosing( WindowEvent e ) {
                window.dispose();
            }
        } );
        app.addMouseMotionListener( app );
        app.addMouseListener( app );
        
    }
    
    private static final long serialVersionUID = 2673458042104218875L;
    
    @Override
    public void paint( Graphics g ) {
        Graphics2D g2 = ( Graphics2D ) g;

        // redraw the draggable shapes in their last dragged position
        draggableShape1 = new RoundRectangle2D.Double( lastDragged1.x,lastDragged1.y,40,20,10,10 );
        g2.setPaint( Color.WHITE );
        g2.fill( draggableShape1 );
        g2.setPaint( Color.BLACK );
        g2.setstroke( new Basicstroke() );
        g2.draw( draggableShape1 );
        
        draggableShape2 = new RoundRectangle2D.Double( lastDragged2.x,lastDragged2.y,10 );
        g2.setPaint( Color.WHITE );
        g2.fill( draggableShape2 );
        g2.setPaint( Color.BLACK );
        g2.setstroke( new Basicstroke( 2.0f,Basicstroke.CAP_BUTT,Basicstroke.JOIN_MITER,20.0f,new float[] { 10.0f / 2.0f },0.0f ) );
        g2.draw( draggableShape2 );
        
        // HERE IS WHERE MY STACKOVERFLOW QUESTION LIES
        // Cancel any drag operation if a dragged object begins to intersect another. 
        // Because then we would have a requirement for differentiating and specifying which object to drag.
        synchronized (this) {
            if ( draggableShape1.getBounds2D().intersects( draggableShape2.getBounds2D() ) ) {
                dragging1 = false;
                dragging2 = false;
                Toolkit.getDefaultToolkit().beep(); // alert the user to termination of the drag
            }
        }
    }

    // Two shapes drawn in method paint()
    private Shape draggableShape1 = null;
    private Shape draggableShape2 = null;
    
    // initial locations of draggable shapes
    private Point initialPosition1 = new Point( 0,0 );
    private Point initialPosition2 = new Point( 100,100 );
    
    // position shape last dropped to
    private Point lastDragged1 = initialPosition1;
    private Point lastDragged2 = initialPosition2;
    
    // is the shape being dragged Now?
    boolean dragging1 = false;
    boolean dragging2 = false;
    
    // During drag,offset between mouse click position and the object being dragged
    int dragMouSEOffsetX = 0;
    int dragMouSEOffsetY = 0;
    
    // Drag event sequence: 
    //      Mouse button down.
    //      Mouse dragged to 1204,452
    //      (repaint called from method mouseDragged )
    //      Mouse button released.

    @Override 
    public void mousepressed(MouseEvent e) {
        System.err.println( "Mouse button down." );
        Point mouseDownPosition = e.getPoint();
        
        // if mouse down in a draggable shape,assume we are starting a drag
        if ( draggableShape1.contains( e.getPoint() ) ) { 
            dragging1 = true;
            // Detect the offset between the mouse position and the shape's top left point
            dragMouSEOffsetX = draggableShape1.getBounds().x - mouseDownPosition.x; // negative is left
            dragMouSEOffsetY = draggableShape1.getBounds().y - mouseDownPosition.y; // negative is up
        }
        
        if ( draggableShape2.contains( e.getPoint() ) ) {
            dragging2 = true;
            // Detect the offset between the mouse position and the shape's top left point
            dragMouSEOffsetX = draggableShape2.getBounds().x - mouseDownPosition.x; // negative is left
            dragMouSEOffsetY = draggableShape2.getBounds().y - mouseDownPosition.y; // negative is up
        }
    }
    
    /**
     * The mouse button is down and is being moved.
     * This has an effect IFF one of the draggable items was under the pointer when the button was pressed
     * */
    @Override
    public void mouseDragged( MouseEvent e ) {
        Point mouseDragPosition = e.getPoint();
        
        if ( dragging1 || dragging2 ) {
            System.err.println( "Mouse dragged to " + mouseDragPosition.x + "," + mouseDragPosition.y );
            System.err.println( "Shape dragged to " + ( mouseDragPosition.x + dragMouSEOffsetX ) + "," + ( mouseDragPosition.y + dragMouSEOffsetY ) );
        }
        
        if ( dragging1 ) { // if we prevIoUsly clicked on the shape
            if ( ! mouseDragPosition.equals( lastDragged1 ) ) { // Ignore drag of less than one pixel (measured in granularity of int)
                Point newDragPoint = new Point( mouseDragPosition.x + dragMouSEOffsetX,mouseDragPosition.y + dragMouSEOffsetY );
                lastDragged1 = newDragPoint;
                repaint();
            }
        }
        
        if ( dragging2 ) { // if we prevIoUsly clicked on the shape
            if ( ! mouseDragPosition.equals( lastDragged2 ) ) { // Ignore drag of less than one pixel (measured in granularity of int)
                lastDragged2 = new Point( mouseDragPosition.x + dragMouSEOffsetX,mouseDragPosition.y + dragMouSEOffsetY );
                repaint();
            }
        }
    }
    
    /**
     * Any time the mouse button comes up,any dragging state is concluded
     * */
    @Override 
    public void mouseReleased(MouseEvent e) {
        System.err.println( "Mouse button released." );
        dragging1 = false;
        dragging2 = false;
    }

    @Override
    public void mouseMoved( MouseEvent e ) {
        // nothing to do
    }
    
    /**
     * The mouse enters or re-enters the application window
     * */
    @Override 
    public void mouseEntered(MouseEvent e) {
        System.err.println( "Mouse entered." );
    }
    
    /**
     * The mouse leaves the application window
     * */
    @Override 
    public void mouseExited(MouseEvent e) {
        System.err.println( "Mouse left." );
    }
     
    /**
     * A combination of mouse down and mouse up has been detected as a click.
     * Not implemented.
     * */
    @Override 
    public void mouseClicked(MouseEvent e) {
        //  Event sequence: 
        //      Mouse button down.
        //      Mouse button released.
        //      Click.
        System.err.println( "Click." );
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。