Comment puis-je utiliser le glisser-déposer dans Swing pour obtenir le chemin du fichier?

StackOverflow https://stackoverflow.com/questions/811248

  •  03-07-2019
  •  | 
  •  

Question

J’ai un JTextField dans mon application Swing qui contient le chemin du fichier du fichier sélectionné à utiliser. Actuellement, j'ai un JFileChooser utilisé pour renseigner cette valeur. Cependant, j'aimerais ajouter la possibilité pour un utilisateur de glisser-déposer un fichier sur ce JTextField et de le placer dans son chemin dans le JTextField au lieu de toujours utiliser JFileChooser.

Comment cela peut-il être fait?

Était-ce utile?

La solution

D'abord, vous devriez vous renseigner sur le prise en charge de Swing DragDrop . . Après cela, il y a quelques petites astuces pour différents systèmes d'exploitation. Une fois que vous avez terminé, vous allez gérer le rappel drop (). Dans ce rappel, vous souhaiterez vérifier le DataFlavor du Transférable.

Pour Windows, vous pouvez simplement vérifier la DataFlavor.isFlavorJavaFileListType () , puis récupérez vos données comme ceci

List<File> dropppedFiles = (List<File>)transferable.getTransferData(DataFlavor.javaFileListFlavor)

Pour Linux (et probablement Solaris), DataFlavor est un peu plus compliqué. Vous devrez créer votre propre DataFlavor et le type Transférable sera différent

nixFileDataFlavor = new DataFlavor("text/uri-list;class=java.lang.String");
String data = (String)transferable.getTransferData(nixFileDataFlavor);
for(StringTokenizer st = new StringTokenizer(data, "\r\n"); st.hasMoreTokens();)
{
    String token = st.nextToken().trim();
    if(token.startsWith("#") || token.isEmpty())
    {
         // comment line, by RFC 2483
         continue;
    }
    try
    {
         File file = new File(new URI(token))
         // store this somewhere
    }
    catch(...)
    {
       // do something good
       ....
    }
}

Autres conseils

Il existe un exemple de programme contenant une classe pouvant être utilisée pour faciliter le glisser-déposer des fichiers et des dossiers:

http://www.iharder.net/current/java/filedrop/

J'ai testé cela avec Windows 7 et Ubuntu 10.10, et cela semble bien fonctionner dans les deux environnements.

Pour l'utiliser, vous ajoutez quelque chose comme ceci à votre code:

  JPanel  myPanel = new JPanel();
  new  FileDrop( myPanel, new FileDrop.Listener()
  {   public void  filesDropped( java.io.File[] files )
      {   
          // handle file drop
          ...
      }   // end filesDropped
  }); // end FileDrop.Listener

Si vous ne souhaitez pas consacrer trop de temps à la recherche sur ce sujet relativement complexe et que vous utilisez Windows (ou Java 7 ou une version ultérieure), voici un exemple rapide expliquant comment accepter les fichiers supprimés avec un JTextArea une cible de largage:

JTextArea myPanel = new JTextArea();
myPanel.setDropTarget(new DropTarget() {
    public synchronized void drop(DropTargetDropEvent evt) {
        try {
            evt.acceptDrop(DnDConstants.ACTION_COPY);
            List<File> droppedFiles = (List<File>)
                evt.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
            for (File file : droppedFiles) {
                // process files
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
});

Je sais que c'est une vieille question, mais les réponses actuelles sont un peu dépassées:

  • depuis JDK 1.6, la classe 'TransferHandler' doit être utilisée avec les nouvelles méthodes (écrasées)
  • la prise en charge de Linux s’est améliorée, pas besoin de gestion personnalisée

Ceci fonctionne sous Linux (KDE5) et Windows 7:

final class FileDropHandler extends TransferHandler {
    @Override
    public boolean canImport(TransferHandler.TransferSupport support) {
        for (DataFlavor flavor : support.getDataFlavors()) {
            if (flavor.isFlavorJavaFileListType()) {
                return true;
            }
        }
        return false;
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean importData(TransferHandler.TransferSupport support) {
        if (!this.canImport(support))
            return false;

        List<File> files;
        try {
            files = (List<File>) support.getTransferable()
                    .getTransferData(DataFlavor.javaFileListFlavor);
        } catch (UnsupportedFlavorException | IOException ex) {
            // should never happen (or JDK is buggy)
            return false;
        }

        for (File file: files) {
            // do something...
        }
        return true;
    }
}

Utilisez-le sur n'importe quel composant avec

myComponent.setTransferHandler(new FileDropHandler());

Cela fonctionne pour moi. Je l'utilise comme ça (scala):

def onDrop(files: List[java.io.File]): Unit = { ... }

    val lblDrop = new Label {
      peer.setTransferHandler(new FileDropHandler(onDrop))
      border = EtchedBorder
    }



class FileDropHandler(val onDrop: List[java.io.File] => Unit) extends javax.swing.TransferHandler {
      import javax.swing.JComponent
      import java.awt.datatransfer.{Transferable, DataFlavor}
        import java.net.URI
    import java.io.File

    val stdFileListFlavor = DataFlavor.javaFileListFlavor
    val nixFileListFlavor = new DataFlavor("text/uri-list;class=java.lang.String")

    override def canImport(comp: JComponent, flavors: Array[DataFlavor]): Boolean =
        flavors.exists(flavor =>
            (flavor == stdFileListFlavor) ||
            (flavor == nixFileListFlavor)
        )

    override def importData(comp: JComponent, t: Transferable): Boolean = {

        val flavors = t.getTransferDataFlavors()

        val files = if (flavors.exists(_ == stdFileListFlavor)) {
            val data = t.getTransferData(stdFileListFlavor)
            importStdFileList( data )
        } else if (flavors.exists(_ == nixFileListFlavor)) {
            val data = t.getTransferData(nixFileListFlavor)
            importNixFileList( data )
        } else List()

        onDrop( files )

        !files.isEmpty
    }

    private def importStdFileList(data: Any): List[File] = {
      data.asInstanceOf[List[File]] //XXX NOT TESTED
    }

    private def importNixFileList(data: Any): List[File] = {

        def clean(rawLine: String): Option[String] = {
            val line = rawLine.trim
            if   (line.length == 0 || line == "#") None
            else                                   Some(line)
        }

        def asURI(line: String): Option[URI] = {
            try   { Some(new URI(line)) }
            catch { case e:Exception => println(e); None }
        }

        def asFile(uri: URI): Option[File] = {
            try   { Some(new File(uri)) }
            catch { case e:Exception => println(e); None }
        }

        data.asInstanceOf[java.lang.String].split("\n")
     .toList flatMap clean flatMap asURI flatMap asFile
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top