将文件从操作系统拖放到Java应用程序(Swing) [英] Drag'n drop files from the OS to Java application (Swing)

查看:74
本文介绍了将文件从操作系统拖放到Java应用程序(Swing)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我首先来说,我一直在阅读 drag' n下载教程和类似的问题,但不幸的是,我对这个问题感到困惑。我想要实现的是比较简单的,所以我很惊讶,这让我陷入了这么多麻烦。我正在编写一个小型实用程序应用程序,它将一堆结果文件(自定义的xml类型)整合到一个大的标签分隔文本文件中。大部分的功能已经被编码了,但是我想为它制作一个体面的GUI。



我想要的是将文件拖放到一个组件中(例如 JTextArea )以一种漂亮和亲切的方式(读取:不是全路径,而是一个小图标和名称)。我想要提供一个 JFileChooser 来浏览文件。然后我将依次解析文件以生成我想要的矩阵。



到目前为止,我学到的是框架已经存在,但是还需要定制其他功能。我在Netbeans中创建了一个测试GUI,并尝试将一堆文件拖到一个 JTextArea 上,但它们显示为文件路径,但诚然,它看起来很丑陋。



我非常感谢任何关于如何以一种整洁的方式解决(或澄清)这个问题的提示和指导。请注意,我打算在多个不同的操作系统(Mac,Win和Linux)上使用该软件。



编辑:远远是基于Sun教程的一个例子,如下所示:

  import java.awt.datatransfer。*; 
import java.awt.event。*;
import java.awt。*;
import java.io. *;
import javax.swing。*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text。*;

public class ConsolidatorDemo extends JPanel实现ActionListener {
private static final long serialVersionUID = -4487732343062917781L;
JFileChooser fc;
JButton清除;
JTextArea dropZone,console;
JSplitPane childSplitPane,parentSplitPane;
PrintStream ps;

public ConsolidatorDemo(){
super(new BorderLayout());

fc = new JFileChooser();;
fc.setMultiSelectionEnabled(true);
fc.setDragEnabled(true);
fc.setControlButtonsAreShown(false);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);


JPanel fcPanel = new JPanel(new BorderLayout());
fcPanel.add(fc,BorderLayout.CENTER);

clear = new JButton(全部清除);
clear.addActionListener(this);
JPanel buttonPanel = new JPanel(new BorderLayout());
buttonPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
buttonPanel.add(clear,BorderLayout.LINE_END);

JPanel leftUpperPanel = new JPanel(new BorderLayout());
leftUpperPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
leftUpperPanel.add(fcPanel,BorderLayout.CENTER);
leftUpperPanel.add(buttonPanel,BorderLayout.PAGE_END);


JScrollPane leftLowerPanel = new javax.swing.JScrollPane();
leftLowerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
dropZone = new JTextArea();
dropZone.setColumns(20);
dropZone.setLineWrap(true);
dropZone.setRows(5);
dropZone.setDragEnabled(true);
dropZone.setDropMode(javax.swing.DropMode.INSERT);
dropZone.setBorder(new TitledBorder(Selected files / folders));
leftLowerPanel.setViewportView(dropZone);

childSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
leftUpperPanel,leftLowerPanel);
childSplitPane.setDividerLocation(400);
childSplitPane.setPreferredSize(new Dimension(480,650));

console = new JTextArea();
console.setColumns(40);
console.setLineWrap(true);
console.setBorder(new TitledBorder(Console));

parentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
childSplitPane,console);
parentSplitPane.setDividerLocation(480);
parentSplitPane.setPreferredSize(new Dimension(800,650));

add(parentSplitPane,BorderLayout.CENTER);

}

public void setDefaultButton(){
getRootPane()。setDefaultButton(clear);
}

public void actionPerformed(ActionEvent e){
if(e.getSource()== clear){
dropZone.setText();

}
}

/ **
*创建GUI并显示它。对于线程安全性,
*此方法应从
*事件调度线程调用。
* /
private static void createAndShowGUI(){
//确保我们有漂亮的窗口装饰。
JFrame.setDefaultLookAndFeelDecorated(true);
try {
//UIManager.setLookAndFeel(\"de.javasoft.plaf.synthetica.SyntheticaBlackStarLookAndFeel);
for(LookAndFeelInfo info:UIManager.getInstalledLookAndFeels()){
if(Nimbus.equals(info.getName())){
UIManager.setLookAndFeel(info.getClassName()) ;
break;
}
}
} catch(Exception e){
e.printStackTrace();
}

//创建并设置窗口。
JFrame frame = new JFrame(Consolidator!);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

//创建并设置菜单栏和内容窗格。
ConsolidatorDemo demo = new ConsolidatorDemo();
demo.setOpaque(true); //内容窗格必须是不透明的
frame.setContentPane(demo);

//显示窗口。
frame.pack();
frame.setVisible(true);
demo.setDefaultButton();
}

public static void main(String [] args){
//为事件调度线程安排一个作业:
//创建并显示此应用程序的GUI。
javax.swing.SwingUtilities.invokeLater(new Runnable(){
public void run(){
createAndShowGUI();
}
});
}


解决方案

这是一个快速的代码片段导入实际的文件到JList(而不是将其String表示形式导入到文本组件中),并使用自定义渲染器来呈现它。它是从BasicDnD(在教程中)改编的:

  fileDropper = new JList(new DefaultListModel()); 
fileDropper.setDragEnabled(true);
leftLowerPanel.setViewportView(fileDropper);

TransferHandler handler = new TransferHandler(){

@Override
public boolean canImport(TransferHandler.TransferSupport info){
//我们只导入FileList
if(!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)){
return false;
}
返回true;
}

@Override
public boolean importData(TransferHandler.TransferSupport info){
if(!info.isDrop()){
return false;
}

//检查FileList flavor
如果(!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)){
displayDropLocation(List不接受drop );
返回false;
}

//获取正在删除的fileList。
可传递t = info.getTransferable();
列表<文件>数据;
try {
data =(List< File>)t.getTransferData(DataFlavor.javaFileListFlavor);
}
catch(异常e){return false; }
DefaultListModel model =(DefaultListModel)fileDropper.getModel();
(文件文件:数据){
model.addElement(file);
}
返回true;
}

private void displayDropLocation(String string){
System.out.println(string);
}
};
fileDropper.setTransferHandler(handler);
fileDropper.setCellRenderer(new DefaultListRenderer(
StringValues.FILE_NAME,IconValues.FILE_ICON));

无法阻止显示SwingX渲染器配置:-)在核心java中,您可以手动,像

  class MyRenderer extends DefaultListCellRenderer {

@Override
public Component getListCellRendererComponent ...){
super.getList ...
if(value instanceof File){
setText(FileSystemView.getFileSystemView()。getDisplayName(value);
setIcon(FileSystemView .getFileSystemView()。getSystemIcon(value);
}
return this;
}

}


Let me start by saying that I have been reading the drag'n drop tutorial and similar questions asked on SO, but unfortunately I have only gotten more confused about this matter. What I want to achieve is relatively simple so I am surprised that it got me in so much trouble already. I am writing a small utility application which will consolidate a bunch of result files (custom defined xml-type) into a large tab-separated text file. Most of the functionality is already coded, however I wanted to make a decent GUI for it.

What I want is to be able to drag'n drop files into a component (for instance JTextArea) in a nice and gracious way (read: not full paths, but instead a small icon and name). I would like to be able to supply a JFileChooser to browse for files as well. I will then parse the files sequentially to produce the matrix I want.

What I have learned so far is that the framework is already there however any additional functionality needs to be custom built. I have created a test GUI in Netbeans and tried to drag a bunch of files onto a JTextArea, but they appear as file paths, and admittedly it looks very ugly.

I would really appreciate any tips and guidance on how to solve (or clarify) this problem in a neat way. Note that I do intend to use the software on multiple different OS (Mac,Win and Linux).

EDIT: the code I have so far is based on one of the examples from Sun tutorials and is as follows

import java.awt.datatransfer.*;
import java.awt.event.*;
import java.awt.*;
import java.io.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.*;

public class ConsolidatorDemo extends JPanel implements ActionListener {
    private static final long serialVersionUID = -4487732343062917781L;
    JFileChooser fc;
    JButton clear;
    JTextArea dropZone, console;
    JSplitPane childSplitPane, parentSplitPane;
    PrintStream ps;

  public ConsolidatorDemo() {
    super(new BorderLayout());

    fc = new JFileChooser();;
    fc.setMultiSelectionEnabled(true);
    fc.setDragEnabled(true);
    fc.setControlButtonsAreShown(false);
    fc.setFileSelectionMode(JFileChooser.FILES_ONLY);               


    JPanel fcPanel = new JPanel(new BorderLayout());
    fcPanel.add(fc, BorderLayout.CENTER);

    clear = new JButton("Clear All");
    clear.addActionListener(this);
    JPanel buttonPanel = new JPanel(new BorderLayout());
    buttonPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    buttonPanel.add(clear, BorderLayout.LINE_END);

    JPanel leftUpperPanel = new JPanel(new BorderLayout());
    leftUpperPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    leftUpperPanel.add(fcPanel, BorderLayout.CENTER);
    leftUpperPanel.add(buttonPanel, BorderLayout.PAGE_END);


    JScrollPane leftLowerPanel = new javax.swing.JScrollPane();
    leftLowerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    dropZone = new JTextArea();
    dropZone.setColumns(20);
    dropZone.setLineWrap(true);
    dropZone.setRows(5);
    dropZone.setDragEnabled(true);
    dropZone.setDropMode(javax.swing.DropMode.INSERT);
    dropZone.setBorder(new TitledBorder("Selected files/folders"));
    leftLowerPanel.setViewportView(dropZone);

    childSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
            leftUpperPanel, leftLowerPanel);
    childSplitPane.setDividerLocation(400);
    childSplitPane.setPreferredSize(new Dimension(480, 650));

    console = new JTextArea();
    console.setColumns(40);
    console.setLineWrap(true);
    console.setBorder(new TitledBorder("Console"));

    parentSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
                    childSplitPane, console);
    parentSplitPane.setDividerLocation(480);
    parentSplitPane.setPreferredSize(new Dimension(800, 650));

    add(parentSplitPane, BorderLayout.CENTER);

}

public void setDefaultButton() {
    getRootPane().setDefaultButton(clear);
}

public void actionPerformed(ActionEvent e) {
    if (e.getSource() == clear) {
        dropZone.setText("");

    }
}

/**
 * Create the GUI and show it. For thread safety,
 * this method should be invoked from the
 * event-dispatching thread.
 */
private static void createAndShowGUI() {
    //Make sure we have nice window decorations.
    JFrame.setDefaultLookAndFeelDecorated(true);
    try {
      //UIManager.setLookAndFeel("de.javasoft.plaf.synthetica.SyntheticaBlackStarLookAndFeel");
        for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    }catch (Exception e){
      e.printStackTrace();
    }

    //Create and set up the window.
    JFrame frame = new JFrame("Consolidator!");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    //Create and set up the menu bar and content pane.
    ConsolidatorDemo demo = new ConsolidatorDemo();
    demo.setOpaque(true); //content panes must be opaque
    frame.setContentPane(demo);

    //Display the window.
    frame.pack();
    frame.setVisible(true);
    demo.setDefaultButton();
}

public static void main(String[] args) {
    //Schedule a job for the event-dispatching thread:
    //creating and showing this application's GUI.
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}

解决方案

here's a quick snippet to import the actual Files into a JList (as opposed to importing its String representation into a text component) and use a custom renderer to present it nicely. It's adapted from the BasicDnD (in the tutorial):

    fileDropper = new JList(new DefaultListModel());
    fileDropper.setDragEnabled(true);
    leftLowerPanel.setViewportView(fileDropper);

    TransferHandler handler =   new TransferHandler() {

        @Override
        public boolean canImport(TransferHandler.TransferSupport info) {
            // we only import FileList
            if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                return false;
            }
            return true;
        }

        @Override
        public boolean importData(TransferHandler.TransferSupport info) {
            if (!info.isDrop()) {
                return false;
            }

            // Check for FileList flavor
            if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                displayDropLocation("List doesn't accept a drop of this type.");
                return false;
            }

            // Get the fileList that is being dropped.
            Transferable t = info.getTransferable();
            List<File> data;
            try {
                data = (List<File>)t.getTransferData(DataFlavor.javaFileListFlavor);
            } 
            catch (Exception e) { return false; }
            DefaultListModel model = (DefaultListModel) fileDropper.getModel();
            for (File file : data) {
                model.addElement(file);
            }
            return true;
        }

        private void displayDropLocation(String string) {
            System.out.println(string);
        }
    };
    fileDropper.setTransferHandler(handler);
    fileDropper.setCellRenderer(new DefaultListRenderer(
          StringValues.FILE_NAME, IconValues.FILE_ICON));

Couldn't resist to showing SwingX renderer config :-) In core java, you would do it manually, something like

   class MyRenderer extends DefaultListCellRenderer {

        @Override
        public Component getListCellRendererComponent(...) {
            super.getList...
            if (value instanceof File) {
                setText(FileSystemView.getFileSystemView().getDisplayName(value);
                setIcon(FileSystemView.getFileSystemView().getSystemIcon(value);
            } 
            return this;
        }

   }

这篇关于将文件从操作系统拖放到Java应用程序(Swing)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆