2017-11-21 11 views
0

私は、removeAll()add()revalidate()のドロップを処理している間に、ドロップが成功し、変更が有効になることに気付きましたが、2度目のドラッグを開始することはできません。それ以降のドラッグの試行ではjava.awt.dnd.InvalidDnDOperationException: Drag and drop in progress が投げられます。Swingドロップコールバック中に、コンポーネント階層の変更が禁止されていますか?

階層に変更を加えてもドラッグはクリアされないと思われ、スイングは進行中のドラッグがまだ完了していないと考えています。これは、階層の変更は問題はドラッグがまだ完了していないときにコンポーネント階層の変更が発生することがありDropTargetDropEvent.acceptDrop()DropTargetDropEvent.dropComplete()

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.dropComplete(true)を呼び出した後、ドロップが完了することができますが、ドラッグ部分は完了しません。現在のDropTargetListener.drop()(EDTが現在実行しているもの)がEDTメインループに制御を戻した後、EDTで実行できる可能性のあるドラッグ側のコールバックがあります。

したがって、コンポーネントの階層の変更は、ドラッグ操作が完了した後に実行されるように遅延される必要があります。

ので、代わりの

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

だけdropComplete()がすでに処理するためにEDTイベントキューにイベントを予定しているので、ドラッグ後に実行することが実行可能なスケジュールます

SwingUtilities.invokeLater(runnable); // unconditionally 

を実行しますドラッグを完​​了します。したがって、invokeLater()は、ドラッグが完了したことを示すイベントの後にコンポーネント階層を変更するコードを配置します。

関連する問題