Как использовать Drag-and-Drop в Swing для получения пути к файлу?
У меня есть JTextField в моем приложении swing, которое содержит путь к файлу файла, выбранного для использования. В настоящее время у меня есть JFileChooser, который используется для заполнения этого значения. Однако я хотел бы добавить возможность для пользователя перетаскивать файл на этот JTextField и помещать путь к файлу этого файла в JTextField, а не всегда использовать JFileChooser.
Как это может быть сделано?
- Как установить цвет для определенной строки, если определенные условия выполняются с помощью java?
- Java: JProgressBar (или эквивалент) в заголовке вкладки JTabbedPane
- компонент java swing не может быть разрешен
- Как лучше всего настроить Swing GUI?
- Как добавить прослушиватель действий, который прослушивает несколько кнопок
- Безопасно ли создавать виджеты Swing / AWT NOT на тему Dispatch Event?
- Получить выделенные строки в JTable с помощью AbstractTableModel
- Как сделать перемещение изображения во время прослушивания нажатия клавиши на Java.
- Изменение размера изображения и отображение в JPanel или JLabel без потери качества
- JButton ActionListener - обновление GUI только после нажатия JButton
- Повернуть BufferedImage внутри JPanel
- Как распечатать одно содержимое JPanel?
- Как «Открыть» и «Сохранить» с помощью java
Сначала вы должны посмотреть поддержку Swing DragDrop . После этого есть несколько небольших трюков для разных операционных систем. Как только у вас все получится, вы будете обрабатывать обратный вызов drop (). В этом обратном вызове вы захотите проверить DataFlavor Transferable.
Для Windows вы можете просто проверить DataFlavor.isFlavorJavaFileListType (), а затем получить свои данные следующим образом
List dropppedFiles = (List )transferable.getTransferData(DataFlavor.javaFileListFlavor)
Для Linux (и, возможно, Solaris) DataFlavor немного сложнее. Вам нужно будет создать свой собственный DataFlavor, а тип Transferable будет отличаться
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 .... } }
Существует примерная программа, которая содержит class, который можно использовать для облегчения перетаскивания файлов и папок:
http://www.iharder.net/current/java/filedrop/
Я тестировал это как с Windows 7, так и с Ubuntu 10.10, и, похоже, он хорошо работает в обеих средах.
Чтобы использовать его, вы добавляете что-то вроде этого в свой код:
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
В случае, если вы не хотите тратить слишком много времени на изучение этого относительно сложного объекта, и вы работаете в Windows (или с использованием Java 7 или более поздней версии), вот краткий пример того, как принимать упавшие файлы с помощью JTextArea в качестве целевой цели :
JTextArea myPanel = new JTextArea(); myPanel.setDropTarget(new DropTarget() { public synchronized void drop(DropTargetDropEvent evt) { try { evt.acceptDrop(DnDConstants.ACTION_COPY); List droppedFiles = (List ) evt.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); for (File file : droppedFiles) { // process files } } catch (Exception ex) { ex.printStackTrace(); } } });
Я знаю, что это старый вопрос, но текущие ответы немного устарели:
- поскольку JDK 1.6 class ‘TransferHandler’ должен использоваться с новыми (перезаписанными) методами
- поддержка Linux стала намного лучше, нет необходимости в пользовательской обработке
Это работает на Linux (KDE5) и 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 files; try { files = (List ) 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; } }
Используйте его на любом компоненте с помощью
myComponent.setTransferHandler(new FileDropHandler());
Это работает для меня. Я использую его так (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 } }