Pregunta

Tengo un JTextField en mi aplicación swing que contiene la ruta del archivo de un archivo seleccionado para ser utilizado. Actualmente tengo un JFileChooser que se utiliza para completar este valor. Sin embargo, me gustaría agregar la capacidad para que un usuario arrastre y suelte un archivo en este JTextField y haga que coloque la ruta del archivo en ese JTextField en lugar de tener que usar siempre el JFileChooser.

¿Cómo se puede hacer esto?

¿Fue útil?

Solución

Primero debes ver compatibilidad con Swing DragDrop . Después de eso, hay algunos pequeños trucos para diferentes sistemas operativos. Una vez que tenga las cosas en marcha, estará manejando la devolución de llamada drop (). En esta devolución de llamada, querrá verificar el DataFlavor del Transferible.

Para Windows solo puede consultar DataFlavor.isFlavorJavaFileListType () y luego obtenga sus datos como este

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

Para Linux (y probablemente Solaris), el DataFlavor es un poco más complicado. Tendrá que hacer su propio DataFlavor y el tipo transferible será diferente

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
       ....
    }
}

Otros consejos

Hay un programa de ejemplo que contiene una clase que se puede utilizar para facilitar la función de arrastrar y soltar archivos y carpetas:

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

Probé esto con Windows 7 y Ubuntu 10.10, y parece funcionar bien en ambos entornos.

Para usarlo, agrega algo como esto a su código:

  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

En caso de que no quieras pasar demasiado tiempo investigando este tema relativamente complejo, y estás en Windows (o usando Java 7 o posterior), aquí tienes un ejemplo rápido sobre cómo aceptar archivos eliminados con un JTextArea como un objetivo de caída:

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();
        }
    }
});

Sé que esta es una pregunta antigua, pero las respuestas actuales están un poco desactualizadas:

  • desde JDK 1.6, la clase 'TransferHandler' debe usarse con nuevos métodos (sobrescritos)
  • el soporte para Linux se volvió mucho mejor, sin necesidad de manejo personalizado

Esto funciona en Linux (KDE5) y 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;
    }
}

Úsalo en cualquier componente con

myComponent.setTransferHandler(new FileDropHandler());

Esto funciona para mí. Lo estoy usando así (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
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top