2014-11-09 3 views
0

내가 응용 프로그램 제공하려면 드래그 앤 드롭하기 위해 드래그 시작을 지연하는 방법 : (여기 사각형)움직임을 결합하여 동적으로

  • 주변의 이미지를 이동할 수 있습니다
  • 그 객체가있는 경우를 작업 영역에서 이동, 캔버스 영역에 객체를 이동하는 동안 너무 빨리 와서 다른 응용 프로그램

을 따라서 자바 FX DragDetected (에 transfere에 대한 끌어서 놓기)를 시작, 내가)합니다 (onDragDetected 억제 처리하고 onMouseDragged() 핸들러에서 MouseDra를 변환하려고했습니다.

event.setDragDetect(true); 

그러나 onDragDetected()가 결코 다시 오실를 사용하여 드래그 이벤트에 g 이벤트 ..... 내가 무엇을 할 수 있습니까?

전체 샘플 응용 프로그램은 다음과 같습니다

package fx.samples; 

import java.io.File; 
import java.util.LinkedList; 

import javax.imageio.ImageIO; 

import javafx.application.Application; 
import javafx.embed.swing.SwingFXUtils; 
import javafx.geometry.Bounds; 
import javafx.geometry.Point2D; 
import javafx.geometry.Rectangle2D; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.SnapshotParameters; 
import javafx.scene.image.WritableImage; 
import javafx.scene.input.ClipboardContent; 
import javafx.scene.input.DataFormat; 
import javafx.scene.input.Dragboard; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.input.TransferMode; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Rectangle; 
import javafx.stage.Stage; 

public class DragRectangle extends Application { 
    Point2D lastXY = null; 

    public void start(Stage primaryStage) { 
     Pane mainPane = new Pane(); 
     Scene scene = new Scene(mainPane, 500, 500); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

     Rectangle area = new Rectangle(0, 0, 500 , 500); 

     Rectangle rect = new Rectangle(0, 0, 30, 30); 
     rect.setFill(Color.RED); 
     mainPane.getChildren().add(rect); 

     rect.setOnMouseDragged(event -> { 
      System.out.println("Move"); 
      Node on = (Node)event.getTarget(); 
      if (lastXY == null) { 
       lastXY = new Point2D(event.getSceneX(), event.getSceneY()); 
      } 
      double dx = event.getSceneX() - lastXY.getX(); 
      double dy = event.getSceneY() - lastXY.getY(); 
      on.setTranslateX(on.getTranslateX()+dx); 
      on.setTranslateY(on.getTranslateY()+dy); 
      lastXY = new Point2D(event.getSceneX(), event.getSceneY()); 
      if (!area.intersects(event.getSceneX(), event.getSceneY(), 1, 1)) { 
       System.out.println("->Drag"); 
       event.setDragDetect(true); 
      } else { 
       event.consume(); 
      } 
     }); 

     rect.setOnDragDetected(event -> { 
      System.out.println("Drag:"+event); 
      if (area.intersects(event.getSceneX(), event.getSceneY(), 1, 1)) { event.consume(); return; } 
      Node on = (Node)event.getTarget(); 
      Dragboard db = on.startDragAndDrop(TransferMode.COPY); 
      db.setContent(makeClipboardContent(event, on, null)); 
      event.consume(); 
     }); 

     rect.setOnMouseReleased(d -> lastXY = null); 
    } 

    public static ClipboardContent makeClipboardContent(MouseEvent event, Node child, String text) { 
     ClipboardContent cb = new ClipboardContent(); 
     if (text != null) { 
      cb.put(DataFormat.PLAIN_TEXT, text); 
     } 
     if (!event.isShiftDown()) { 
      SnapshotParameters params = new SnapshotParameters(); 
      params.setFill(Color.TRANSPARENT); 
      Bounds b = child.getBoundsInParent(); 
      double f = 10; 
      params.setViewport(new Rectangle2D(b.getMinX()-f, b.getMinY()-f, b.getWidth()+f+f, b.getHeight()+f+f)); 

      WritableImage image = child.snapshot(params, null); 
      cb.put(DataFormat.IMAGE, image); 

      try { 
       File tmpFile = File.createTempFile("snapshot", ".png"); 
       LinkedList<File> list = new LinkedList<File>(); 
       ImageIO.write(SwingFXUtils.fromFXImage(image, null), 
         "png", tmpFile); 
       list.add(tmpFile); 
       cb.put(DataFormat.FILES, list); 
      } catch (Exception e) { 

      } 
     } 
     return cb; 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

답변

0

this 기준 자료 :

기본 드래그 감지 메커니즘 히스테리시스 조합에 눌러 진 버튼으로 마우스의 움직임을 사용합니다. 이 동작은 응용 프로그램에 의해 보강 될 수 있습니다. 각 MOUSE_PRESSED 및 MOUSE_DRAGGED 이벤트에는 드래그 동작이 감지되었는지 여부를 결정하는 dragDetect 플래그가 있습니다. 이 플래그의 기본값은 기본 검색 메커니즘에 따라 다르며 이벤트 핸들러 내에서 setDragDetect()를 호출하여 수정할 수 있습니다. 이러한 이벤트 중 하나의 처리가 true로 설정된 dragDetect 플래그로 끝나면 DRAG_DETECTED MouseEvent가 잠재적 제스처 소스 (마우스 버튼이 눌려진 객체)로 전송됩니다. 이 이벤트는 제스처 감지에 대해 알립니다. 단지의 mouseDragged 후 어느 시점 에서 setDragDetect(true)을 가능하게

당신의 가정은 드래그 이벤트가 발생합니다를 시작, 작동하지 않습니다.

이유는 개인 DragDetectedState 플래그가 있기 때문에 제스처 시작 부분에 끌기 상태를 설정하는 데 사용됩니다. 일단 이미 선택 되었으면 변경할 수 없습니다. 이벤트가가 트리거되어 있지 않은 경우

그래서, 당신이 할 수있는 것은 스스로를 트리거 수동입니다 : 드래그 dectected 이벤트를

if (!area.intersects(event.getSceneX(), event.getSceneY(), 1, 1)) { 
     System.out.println("->Drag"); 
     event.setDragDetect(true); 
     Event.fireEvent(rect, new MouseEvent(MouseEvent.DRAG_DETECTED, 0, 0, 0, 0, MouseButton.PRIMARY, 0, false, false, false, false, true, false, false, true, true, true, null)); 
    } 

이 효과적으로 실행할 것이며, rect.setOnDragDetected()가 호출됩니다.

그러나 이것은 당신이 얻을 것이다 무엇 :

Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException: 
    Cannot start drag and drop outside of DRAG_DETECTED event handler 
at javafx.scene.Scene.startDragAndDrop(Scene.java:5731) 
at javafx.scene.Node.startDragAndDrop(Node.java:2187) 

기본적으로, 당신은 MouseDragged의와 DragDetected을 결합 할 수 있으며, startDragAndDrop 방법은 Drag_Detected event 내에서 호출해야하기 때문에 :

확인 이 노드 위에 인식되는 잠재적 드래그 앤 드롭 제스처. DRAG_DETECTED 이벤트 핸들러에서만 호출 할 수 있습니다.

두 개의 다른 이벤트를 결합하지 말고, 감지 된 이벤트를 드래그하여 장면이나 부분이 드롭을 허용하고 동시에 노드를 변환하는 것이 좋습니다. 드래그 & 드롭이 장면을 벗어나면 새 대상에 파일을 놓을 수 있습니다. 이 같은

뭔가 :

@Override 
public void start(Stage primaryStage) { 
    Pane mainPane = new Pane(); 

    Rectangle rect = new Rectangle(0, 0, 30, 30); 
    rect.setFill(Color.RED); 
    mainPane.getChildren().add(rect); 

    Scene scene = new Scene(mainPane, 500, 500); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 

    rect.setOnDragDetected(event -> { 
     Node on = (Node)event.getSource(); 
     Dragboard db = on.startDragAndDrop(TransferMode.ANY); 
     db.setContent(makeClipboardContent(event, on, null)); 
     event.consume(); 
    }); 

    mainPane.setOnDragOver(e->{ 
     e.acceptTransferModes(TransferMode.ANY); 
    }); 

    mainPane.setOnDragExited(e->{ 
     rect.setLayoutX(e.getSceneX()-rect.getWidth()/2d); 
     rect.setLayoutY(e.getSceneY()-rect.getHeight()/2d); 
    }); 
} 
+0

"당신의 가정 () 어떤 시점에서 드래그 이벤트가 작동하지 않습니다. " -> 히스테리시스로 끌기가 시작되기 전에 (내가 첫 번째 이동 이벤트에서 드래그를 시작하기 전에) 그렇게하면 작동합니다 ... 그래서 나중에도 작동하기를 바랍니다. –

+0

나는 fireEvent()를 사용하여 이미 다음과 같은 결과를 얻었습니다. Exception "DRAG_DETECTED 이벤트 핸들러 외부로 드래그 앤 드롭을 시작할 수 없습니다"... (슬픈 방법) –

+0

내 응용 프로그램에서 드래그 앤 드롭을 처음 구현했습니다. ,하지만 그것은 객체의 드래그 된 아이콘이 즉시 가운데에 위치하므로 매우 나쁜 사용자 피드백을 제공하고, 이미지가 더 크면 축소되어 표시됩니다. 따라서 드롭에 대한 정확한 배치는 사용자에게 알려지지 않습니다. 그래서 나는 이동 중에 응용 프로그램이 남아있을 경우에만 끌기를 시작하기로 결정했습니다. 도움을 주셔서 감사합니다,하지만 난 여전히이 문제에 대한 해결책이 필요합니다. –

1

좋아, 나는 그 마지막 쉽게 ... 약간의 시간이 자바 FX 소스를 읽고하는 EventDispatcher 등으로 arround를 재생 지출 :

짧은에서 :

억제 시스템은 onMouseDragged() 핸들러에서 start 제안을 드래그하고 대신에 해당 플래그를 설정합니다.

긴 텍스트 :

DragDetected를 시작하는 메커니즘은 결과적으로 MouseEvent MOUSE_DRAGGED를 사용합니다.

 if (dragDetected != DragDetectedState.NOT_YET) { 
      mouseEvent.setDragDetect(false); 
      return; 
     } 

     if (mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED) { 
      pressedX = mouseEvent.getSceneX(); 
      pressedY = mouseEvent.getSceneY(); 

      mouseEvent.setDragDetect(false); 

     } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED) { 

      double deltaX = Math.abs(mouseEvent.getSceneX() - pressedX); 
      double deltaY = Math.abs(mouseEvent.getSceneY() - pressedY); 
      mouseEvent.setDragDetect(deltaX > hysteresisSizeX || 
            deltaY > hysteresisSizeY); 

     } 
    } 

하고 정상적인 MOUSE_DRAG 이벤트

mouseEvent.setDragDetect(true) 

을 설정 : 현재 마우스 드래그 여기에 드래그로 원래의 코드를 해석 될 경우 시스템 드래그 감지 결정하기 위해 몇 가지 규칙을 적용합니다 . 해당 이벤트는 전달되고 모든 '다운 체인'EventDispatcher에 의해 처리됩니다 ...이 이벤트가 최종적으로 처리를 위해 도착하고 isDragDetect 플래그가 여전히 true 인 경우 후속 DragDetected 이벤트가 생성됩니다.

 mainPane.setEventDispatcher((event, chain) -> { 
      switch (event.getEventType().getName()) { 
       case "MOUSE_DRAGGED": 
        MouseEvent drag = (MouseEvent)event; 

        drag.setDragDetect(false); 
        if (!area.intersects(drag.getSceneX(), drag.getSceneY(), 1, 1)) { 
         System.out.println("->Drag down"); 
         drag.setDragDetect(true); 
        } 
        break; 
      } 

      return chain.dispatchEvent(event); 
     }); 

을 그리고이 코드는 드래그 상태에 도달 할 것을 결정하면, 단순히 플래그를 설정합니다

그래서 나는 아래로하는 EventDispatcher를 사용하여 길에 isDragDetect 플래그를 취소하여 DragDetected을 지연 할 수 있어요.
 drag.setDragDetect(true); 

는 지금은 정확하게 내 개체를 이동하고이 애플리케이션 영역 외부로 이동하는 경우 드래그를 시작할 수입니다.

그리고 생각의 일부 분

:는 EventDispatcher 모두가 ... onMouseDragged 핸들러에서 수행 할 수 있습니다, 필요하지 않습니다

전체 코드 : 사실 단지 setDragDetect을 가능하게

package fx.samples; 

import java.io.File; 
import java.util.LinkedList; 

import javafx.application.Application; 
import javafx.embed.swing.SwingFXUtils; 
import javafx.geometry.Bounds; 
import javafx.geometry.Point2D; 
import javafx.geometry.Rectangle2D; 
import javafx.scene.Node; 
import javafx.scene.Scene; 
import javafx.scene.SnapshotParameters; 
import javafx.scene.image.WritableImage; 
import javafx.scene.input.ClipboardContent; 
import javafx.scene.input.DataFormat; 
import javafx.scene.input.Dragboard; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.input.TransferMode; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Rectangle; 
import javafx.stage.Stage; 

import javax.imageio.ImageIO; 


public class DragRectangle extends Application { 
    Point2D lastXY = null; 

    public void start(Stage primaryStage) { 
     Pane mainPane = new Pane(); 
     Scene scene = new Scene(mainPane, 500, 500); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

     Rectangle area = new Rectangle(0, 0, 500 , 500); 

     Rectangle rect = new Rectangle(0, 0, 30, 30); 
     rect.setFill(Color.RED); 
     mainPane.getChildren().add(rect); 

     rect.setOnMouseDragged(event -> { 
      System.out.println("Move"); 
      event.setDragDetect(false); 
      Node on = (Node)event.getTarget(); 
      if (lastXY == null) { 
       lastXY = new Point2D(event.getSceneX(), event.getSceneY()); 
      } 
      double dx = event.getSceneX() - lastXY.getX(); 
      double dy = event.getSceneY() - lastXY.getY(); 
      on.setTranslateX(on.getTranslateX()+dx); 
      on.setTranslateY(on.getTranslateY()+dy); 
      lastXY = new Point2D(event.getSceneX(), event.getSceneY()); 
      if (!area.intersects(event.getSceneX(), event.getSceneY(), 1, 1)) event.setDragDetect(true); 
      event.consume(); 
     }); 

     rect.setOnDragDetected(event -> { 
      System.out.println("Drag:"+event); 
      Node on = (Node)event.getTarget(); 
      Dragboard db = on.startDragAndDrop(TransferMode.COPY); 
      db.setContent(makeClipboardContent(event, on, "red rectangle")); 
      event.consume(); 
     }); 

     rect.setOnMouseReleased(d -> lastXY = null); 
    } 

    public static ClipboardContent makeClipboardContent(MouseEvent event, Node child, String text) { 
     ClipboardContent cb = new ClipboardContent(); 
     if (text != null) { 
      cb.put(DataFormat.PLAIN_TEXT, text); 
     } 
     if (!event.isShiftDown()) { 
      SnapshotParameters params = new SnapshotParameters(); 
      params.setFill(Color.TRANSPARENT); 
      Bounds b = child.getBoundsInParent(); 
      double f = 10; 
      params.setViewport(new Rectangle2D(b.getMinX()-f, b.getMinY()-f, b.getWidth()+f+f, b.getHeight()+f+f)); 

      WritableImage image = child.snapshot(params, null); 
      cb.put(DataFormat.IMAGE, image); 

      try { 
       File tmpFile = File.createTempFile("snapshot", ".png"); 
       LinkedList<File> list = new LinkedList<File>(); 
       ImageIO.write(SwingFXUtils.fromFXImage(image, null), 
         "png", tmpFile); 
       list.add(tmpFile); 
       cb.put(DataFormat.FILES, list); 
      } catch (Exception e) { 

      } 
     } 
     return cb; 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

이벤트 발송자는 훌륭하게 작동합니다. 결국 당신은 드래그 감지 플래그를 거짓으로 유지해야합니다. 그건 그렇고, 당신은 이것을 고려할 수 있습니다 :'db.setDragView (image, event.getX(), event.getY());'드래그 한 노드로 끌어온 노드 이미지로 이미지를 부드럽게 전환 할 수있게합니다. 장면 좌표를 사용할 수 없습니다. –

관련 문제