2017-08-31 14 views
0

ここでエラーはjava.awt.dnd.InvalidDnDOperationException: The operation requested cannot be performed by the DnD system since it is not in the appropriate stateです。このエラーは、プログラムの中にファイルをいくつかドロップすると表示されます(デスクトップから取得)。私はNautilusでUbuntu 16.04を使用しています。AWTのJavaでのドラッグアンドドロップで奇妙なエラーが発生する

import javax.swing.*; 
import java.awt.datatransfer.DataFlavor; 
import java.awt.dnd.*; 
import java.io.File; 
import java.util.List; 

class UI extends JFrame { 
List<File> droppedFiles; 

UI(){ 
    super("My Program"); 
    this.setDefaultCloseOperation(EXIT_ON_CLOSE); 
    this.setLayout(null); 
    this.setVisible(true); 
    this.setResizable(true); 
    this.setSize(800, 500); 
    this.setExtendedState(MAXIMIZED_BOTH); 
    JTextField dropArea = getDropArea(); 
    this.add(dropArea); 
} 

private JTextField getDropArea(){ 
    JTextField dropArea = new JTextField("Drop file here"); 
    dropArea.setBounds(50, 50, 200, 200); 
    dropArea.setDropTarget(createNewDropTarget(dropArea)); 

    return dropArea; 
} 

private DropTarget createNewDropTarget(JTextField dropArea) { 
    DropTarget dt = new DropTarget(){ 
     @Override 
     public synchronized void drop(DropTargetDropEvent dtde) { 
      super.drop(dtde); 
      try { 
       dtde.acceptDrop(DnDConstants.ACTION_COPY); 
       droppedFiles = (List<File>) dtde.getTransferable(). 
         getTransferData(DataFlavor.javaFileListFlavor); 
       dropArea.setText(droppedFiles.get(0).getName()); 
      }catch (Exception e){ 
       e.printStackTrace(); 
      } 
     } 
    }; 
    return dt; 
} 
} 

エラーは、droppedFilesが初期化された行に表示されます。 (try catchブロック内)。

答えて

2

DropTargetを設定する方法では、super.drop(dtde);に電話する必要はありません。これが実際に例外の理由です。ここDropTarget.drop()の実装です:

public synchronized void drop(DropTargetDropEvent dtde) { 
    clearAutoscroll(); 

    if (dtListener != null && active) 
     dtListener.drop(dtde); 
    else { // we should'nt get here ... 
     dtde.rejectDrop(); 
    } 
} 

ドロップが拒否され、後続の呼び出しgetTransferable()InvalidDnDOperationExceptionで失敗リスナーでたDropTargetを初期化されていませんので。あなたがsuper.drop(dtde);とコメントした場合、問題はなくなるはずです。よりクリーンな方法は、リスナーを作成してDropTargetに渡すことです。ここで小さな例です:

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.datatransfer.DataFlavor; 
import java.awt.dnd.DnDConstants; 
import java.awt.dnd.DropTarget; 
import java.awt.dnd.DropTargetAdapter; 
import java.awt.dnd.DropTargetDropEvent; 
import java.io.File; 
import java.util.List; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTextField; 
import javax.swing.SwingUtilities; 

public class DDTest extends JPanel { 
    public DDTest() { 
     setLayout(new BorderLayout()); 
     final JTextField dropArea = new JTextField("Drop file here"); 
     add(dropArea); 
     new DropTarget(dropArea, new DropTargetAdapter() { 
      @Override 
      public void drop(DropTargetDropEvent dtde) { 
       try { 
        dtde.acceptDrop(DnDConstants.ACTION_COPY); 
        List<File> droppedFiles = (List<File>) dtde 
          .getTransferable().getTransferData(
            DataFlavor.javaFileListFlavor); 
        dropArea.setText(droppedFiles.get(0).getName()); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      }   
     }); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(300, 200); 
    } 

    private static void createAndShowGUI() { 
     final JFrame frame = new JFrame("DDTest"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     frame.add(new DDTest()); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 
} 

PS:absolute layoutを使用すると複雑になることがあり、通常は回避することができる

注意。いくつかのアイデアについては、A Visual Guide to Layout Managersを参照してください。

関連する問題