2017-11-21 7 views
0

removeAll(), add(), revalidate()을 처리하는 동안 드롭 DropTargetListener.drop()을 처리하면 드롭이 성공하고 변경 사항이 적용되지만 두 번째 드래그를 절대 시작할 수 없음을 발견했습니다. 이후의 드래그 시도는 java.awt.dnd.InvalidDnDOperationException: Drag and drop in progress 이됩니다.스윙 드롭 콜백 중에 컴포넌트 계층 변경이 금지되어 있습니까?

계층 구조를 변경하면 끌기가 지워지지 않으며 스윙은 진행중인 드래그가 완료 될 때까지 계속 진행중인 것으로 생각합니다. 계층 구조 변경

import javax.swing.*; 
import javax.swing.event.*; 
import java.awt.*; 
import java.awt.dnd.*; 
import javax.activation.*; 
import java.awt.datatransfer.*; 
import java.util.TooManyListenersException; 


class MyWidget extends JComponent { 

    MyWidget() { 
     setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 
     updateState(); 
    } 

    void updateState() { 
     Runnable runnable = new Runnable() { 
      @Override 
      public void run() { 
       // System.out.println("Hello World on " + Thread.currentThread()); 
       removeAll(); 
       add(newButton("aaa")); 
       add(newButton("bbb")); 
       revalidate(); 

      } 
     }; 
     if (SwingUtilities.isEventDispatchThread()) { 
      runnable.run(); 
     } else { 
      SwingUtilities.invokeLater(runnable); 
     } 

    } 

    JButton newButton(String text) { 
     JButton theButton = new JButton(text); 

     DragSource ds = new DragSource(); 
     DragGestureRecognizer dgr = ds.createDefaultDragGestureRecognizer(theButton, DnDConstants.ACTION_COPY, new DragGestureListener() { 
      @Override 
      public void dragGestureRecognized(DragGestureEvent dge) { 
       Transferable transferable = new DataHandler("my text", "text/plain"); 
       dge.startDrag(DragSource.DefaultCopyDrop, transferable); 
      } 
     }); 

     DropTarget dt = new DropTarget(); 
     dt.setComponent(theButton); 
     try { 
     dt.addDropTargetListener(new DropTargetAdapter() { 
      @Override 
      public void drop(DropTargetDropEvent dtde) { 
      System.out.println("drop accepted"); 
      dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); 
      dtde.dropComplete(true); 
      updateState(); 
      } 
     }); 
     } catch (TooManyListenersException e) {} 
     return theButton; 
    } 

} 

public class App 
{ 
    static void createGUI() { 
     JFrame frame = new JFrame(); 
     frame.setTitle("my app"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(new MyWidget(), BorderLayout.CENTER); 
     frame.setSize(500,500); 
     // frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       System.out.println("Hello World on " + Thread.currentThread()); 
       createGUI(); 
      } 
     }); 
    } 
} 

답변

1

문제 DropTargetDropEvent.acceptDrop()DropTargetDropEvent.dropComplete()를 호출 한 후 경우에도이 드래그가 아직 완료되지 않은 상태에서 구성 요소 계층 구조 변경이 발생한다는 것입니다 발생합니다. DropTargetDropEvent.dropComplete(true)을 호출 한 후에 드롭이 완료 될 수 있지만 드래그 부분은 완료되지 않을 수 있습니다. 현재 DropTargetListener.drop() (EDT가 현재 실행중인)이 EDT 기본 루프에 제어를 반환 한 후 EDT에서 잠재적으로 실행할 수있는 드래그쪽에 콜백이 있습니다.

따라서 구성 요소 계층 구조 변경은 드래그 작업이 완료된 후에 실행되도록 지연되어야합니다.

그래서 대신

if (SwingUtilities.isEventDispatchThread()) { 
    runnable.run(); 
} else { 
    SwingUtilities.invokeLater(runnable); 
} 

은 실행

SwingUtilities.invokeLater(runnable); // unconditionally 
dropComplete() 이미를 처리하기 위해 EDT 이벤트 큐에서 이벤트를 계획했기 때문에, 드래그 한 후 실행하는 실행 가능한 일정을 계획 할 것

드래그 완료. 따라서 invokeLater()은 드래그를 완료로 표시 할 이벤트 이후에 구성 요소 계층 구조를 변경하는 코드를 삽입합니다.