Java 7:如何在 Java 中实现拖放?

     2023-05-08     84

关键词:

【中文标题】Java 7:如何在 Java 中实现拖放?【英文标题】:Java 7: How to implement drag & drop in Java? 【发布时间】:2013-04-25 15:06:25 【问题描述】:

我目前正在使用 Java 7 Update 21 进行拖放试验。

我的目标操作系统是:

Windows 7 Ubuntu 12.04 Mac OSX 10.6 / 10.8

要求是:

将文件从文件系统中拖放到我的 Java 应用程序中(制作一个 将文件复制到临时目录)-> 适用于 Linux & MacOSX & Windows

将电子邮件从 Thunderbird 拖放到我的 Java 应用程序(保存 它们作为文件系统上的完整 *.eml 文件)

以下代码适用于我的 Windows、MacOSX Ubuntu 应用程序的简单文件拖放。另一个要求是将电子邮件从 Thunderbird 放到我的 Java 应用程序中(邮件会自动转换为 *.eml 文件并存储到磁盘中)。这也适用于 Windows,但我在 Ubuntu 和 MacOSX 中得到 "Data Flavor not supported exception"...

编辑:我在 Ubuntu 上使用 OpenJDK 7 进行了尝试,但是这样,即使是正常的文件删除也不起作用。仅适用于 JDK 版本的 Oracle。

有人知道如何解决/实现这一点吗?

非常感谢!

这是一个简单的可执行示例:

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;


public class DragDropTest extends javax.swing.JFrame 


    public DragDropTest() 
        initComponents();
        initDragAndDrop();
    

    private void initDragAndDrop() 
        this.setDropTarget(new DropTarget()
            @Override
            public synchronized void drop(DropTargetDropEvent dtde) 
                try 
                    Transferable transfer = dtde.getTransferable();
                    if(transfer.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) 
                        dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                        List objects = (List)transfer.getTransferData(DataFlavor.javaFileListFlavor);
                        for(Object object : objects) 
                            if(object instanceof File) 
                                File source = (File)object;
                                File dest = new File(System.getProperty("user.home")+File.separator+source.getName());
                                Files.copy(Paths.get(source.getAbsolutePath()), Paths.get(dest.getAbsolutePath()), StandardCopyOption.REPLACE_EXISTING);
                                System.out.println("File copied from "+source.getAbsolutePath()+" to "+dest.getAbsolutePath());
                            
                        
                     else if(transfer.isDataFlavorSupported(DataFlavor.stringFlavor)) 
                        dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                        String type = (String)transfer.getTransferData(DataFlavor.stringFlavor);
                        System.err.println("Data flavor not supported: "+type);
                     else 
                        System.err.println("Data flavor not supported.");
                    
                 catch(UnsupportedFlavorException ex) 
                    System.err.println(ex.getMessage());
                 catch(IOException ex) 
                    System.err.println(ex.getMessage());
                 catch(Exception ex) 
                    System.err.println(ex.getMessage());
                 finally 
                    dtde.dropComplete(true);
                
            
        );
    

    @SuppressWarnings("unchecked")                      
    private void initComponents() 

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Drag & Drop");
        setResizable(false);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 200, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 200, Short.MAX_VALUE)
        );

        pack();
                           

    public static void main(String args[]) 
        new DragDropTest().setVisible(true);
    


【问题讨论】:

【参考方案1】:

实际上问题不在于您的 Java 代码...这是 ubuntu 本身的一个错误,而 Ubuntu Unity 不支持跨两个 Windows 拖放(在您的应用程序中 Mozilla Thunderbird 和 Java App 之间)。虽然可以将文件从文件系统拖放到窗口中..

要确认这一点,请尝试将邮件文件从 Thunderbird 拖到浏览器窗口作为 Gmail 附件,,但它不起作用。

为了跟上这个错误审查 Ubuntu Bugs Launchpad 中的错误更新来自: https://bugs.launchpad.net/unity/+bug/995039

【讨论】:

感谢您的建议。我尝试使用“sudo apt-get purge mousetweaks”删除 Mousetweaks。但它仍然不起作用...... :-(【参考方案2】:

与其扔,不如打印出你在可转移设备上获得的数据类型,看看是否有你可以使用的。比如,

 else  
      for(DataFlavor f : transfer.getTransferDataFlavors()) 
             System.out.println("flavor f:" + f + " type:" + f.getMimeType() + " javaClas:" + f.getDefaultRepresentationClass());  
      
 

鉴于该输出,您很有可能会看到如何将其保存到文件中。

【讨论】:

进一步打印你得到的味道并尝试操纵它,也许将所有内容保存到文件中,然后看看什么是 .eml 虽然我怀疑只会设置一个。如果你没有得到任何可用的东西可能是 *nix 的雷鸟的问题【参考方案3】:

我想下面的链接会让你对这个问题有所了解:-

http://softwareisart.blogspot.in/2011/11/drag-and-drop-of-complex-custom-objects.html

【讨论】:

【参考方案4】:

这是我目前最终解决问题的方法。

    如果不支持 file-list-flavor,则从 drop-event 获取 imap URL 使用 imap URL 中提供的信息打开 imap 连接 打开 imap-store、imap-folder,通过 UID 搜索消息,最后获取消息 转换为 *.eml 格式

所需库:Apache Commons I/O 和 Java Mail API

下面是drop事件的实现:

scrDocuments.setDropTarget(new DropTarget() 
        @Override
        public synchronized void drop(DropTargetDropEvent evt) 
            try 
                Transferable transfer = evt.getTransferable();
                if(transfer.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) 
                    evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                    List objects = (List)transfer.getTransferData(DataFlavor.javaFileListFlavor);
                    for(Object object : objects) 
                        if(object instanceof File) 
                            File file = (File)object;
                            // store file ...
                        
                    
                 else 
                    try 
                        String url = fetchURL(evt, transfer);
                        ImapMessage eml = new ImapMessage(url);
                        File file = eml.fetchMessage();
                        // store file ...
                     catch(Exception ex) 
                        System.err.println(ex.getMessage());
                    
                
             catch(Exception ex) 
                System.err.println(ex.getMessage());
             finally 
                evt.dropComplete(true);
            
        
    );

private String fetchURL(DropTargetDropEvent evt, Transferable transfer) throws IOException, UnsupportedEncodingException, UnsupportedFlavorException 
    for(DataFlavor flavor : transfer.getTransferDataFlavors()) 
        if(flavor.isRepresentationClassInputStream()) 
            if(flavor.getHumanPresentableName().equals("application/x-moz-file-promise-url")) 
                evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
                BufferedReader reader = new BufferedReader(new InputStreamReader((InputStream)transfer.getTransferData(flavor), "ISO-8859-1"));
                String fAddress = reader.readLine();
                reader.close();
                return fAddress;
            
        
    
    throw new IOException("No transferable object or stream found.");

以下类查找 imap 服务器并获取邮件:

public class ImapMessage 

    private String authority;
    private String protocol;
    private String host;
    private int port;
    private String username;
    private String password;
    private String foldername;
    private long msgid;
    private String filename;
    private Message message;

    public ImapMessage(String url) throws IOException, MessagingException 
        parseURL(decodeURL(url));
    

    @Override
    public String toString() 
        return "protocol: "+protocol+"\n"+
               "host: "+host+"\n"+
               "port: "+port+"\n"+
               "username: "+username+"\n"+
               "password: "+password+"\n"+
               "folder: "+foldername+"\n"+
               "msgid: "+msgid+"\n"+
               "filename: "+filename;
    

    private String decodeURL(String url) throws IOException 
        if(url!=null && !url.isEmpty()) 
            String newurl = "";
            for(int i=0; i<url.length(); i+=2) 
                newurl+=url.substring(i, i+1);
            
            newurl = StringUtils.replace(newurl, "%3E", ">");
            newurl = StringUtils.replace(newurl, "%20", " ");
            return newurl;
         else 
            throw new IOException("The given URL is empty or invalid.");
        
    


    private void parseURL(String url) throws IOException, MalformedURLException 
        if(url!=null && !url.isEmpty()) 
            //<editor-fold defaultstate="collapsed" desc="Parse Protocol">
            if(url.startsWith("imaps")) 
                url = StringUtils.replace(url, "imaps", "http", 1);
                protocol = "imaps";
             else if(url.startsWith("imap")) 
                url = StringUtils.replace(url, "imap", "http", 1);
                protocol = "imap";
             else 
                throw new IOException("Unsupported protocol: "+url.substring(0, url.indexOf("://")));
            

            try 
                URL newurl = new URL(url);
                String path = newurl.getPath();
                String query = newurl.getQuery();
                authority = newurl.getAuthority();
                host = newurl.getHost();
                port = newurl.getPort();
                username = newurl.getUserInfo();
                password = "provide your password here";
                foldername = path.substring(path.indexOf(">/")+2, path.lastIndexOf(">"));
                msgid = Long.parseLong(path.substring(path.lastIndexOf(">")+1, path.length()));
                filename = query.substring(query.indexOf("=")+1, query.length());
             catch (MalformedURLException ex) 
                throw ex;
            
         else 
            throw new IOException("The given URL is empty or invalid.");
        
    

        public File fetchMessage() throws IOException, FileNotFoundException, MessagingException 

            Store store = null;
            Folder folder = null;
            File filepath = new File("/destination/directory");
            try 
                Properties props = System.getProperties();
                props.setProperty("mail.store.protocol", protocol);
                Session session = Session.getDefaultInstance(props, null);
                // session.setDebug(true);
                store = session.getStore(protocol);
                store.connect(host, port, username, password);
                folder = store.getFolder(foldername);
                folder.open(Folder.READ_ONLY);
                UIDFolder ufolder = (UIDFolder)folder;
                message = ufolder.getMessageByUID(msgid);
                if(message!=null) 
                    File file = null;
                    if(filename.equals("null")) 
                        file = new File(filepath.getAbsolutePath()+File.separator+Long.toString(System.nanoTime())+".eml");
                     else 
                        file = new File(filepath.getAbsolutePath()+File.separator+filename);
                    
                    message.writeTo(new FileOutputStream(file));
                    return file;
                 else 
                    throw new MessagingException("The requested e-mail could not be found on the mail server.");
                
             catch(Exception ex) 
                throw ex;
             finally 
                if(folder!=null) 
                    folder.close(true);
                
                if(store!=null) 
                    store.close();
                
            
        

    

【讨论】:

在 Gingerbread 中实现拖放

...【发布时间】:2012-02-0620:19:10【问题描述】:我需要知道如何在Android中为Gingerbread版本实现拖放。据我所知,Gingerbread默认不支持。我编码的内容:一个ViewGroup类来保存动态添加的孩子,每个孩子都应该在长按后能够通过手指点... 查看详情

在 NSTableView 中实现拖放

】在NSTableView中实现拖放【英文标题】:ImplementingdraganddropinNSTableView【发布时间】:2011-08-2206:29:32【问题描述】:谁能帮我?我在下面使用了这段代码,但这些方法在执行期间没有被调用。-(BOOL)tableView:(NSTableView*)tvwriteRowsWithIndexe... 查看详情

有没有办法在 phonegap angular js 项目中实现拖放?

】有没有办法在phonegapangularjs项目中实现拖放?【英文标题】:Isthereawaytoimplementdrag&dropinaphonegapangularjsproject?【发布时间】:2014-12-0116:27:04【问题描述】:我试过这个:https://github.com/codef0rmer/angular-dragdrop和touchpunch(http://touchpunc... 查看详情

在 Avalonia 中实现 TreeView 节点的拖放

...nodesinAvalonia【发布时间】:2017-11-1013:03:56【问题描述】:如何在TreeView控件中实现拖放行为?一个例子是文件浏览器,用户可以通过拖动将文件从一个文件夹移动到另一个文件夹。我的XAML中有以下代码:<TreeViewItems="BindingRootFil... 查看详情

如何在图像上实现拖放,改变其位置

】如何在图像上实现拖放,改变其位置【英文标题】:Howtoimplementdrag&Droponanimage,changingitsposition【发布时间】:2020-06-0119:58:09【问题描述】:我开发了一个滑块,向我展示了几张图片。在顶部(大图像和滑块所在的位置)我将... 查看详情

如何在unity中实现拖尾效果

...会添加拖尾或者鼠标点击的特效,接下来就说说在unity中如何实现拖尾效果,首先unity中有个组件,叫TrailRenderer,在Component——>Effect——>TrailRenderer中添加,根据自己需要的效果设置自己需要的颜色,然后还有相... 查看详情

html5中的拖放

(1)在HTML5中实现拖放需要将目标元素的"draggable"属性设置为"true";(2)元素拖放时触发的相关事件: a:dragstart——在开始拖放被拖放元素时触发(事件主体:被拖放元素);b:drag——正在拖放被拖放元素触发(事件主体... 查看详情

如何在vue中实现拖拽(代码片段)

1、npmi vuedraggable2、在组件中引入importvuedraggablefrom'vuedraggable';3、<template><vuedraggableclass="wrapper"v-model="list"><transition-group><divv-for& 查看详情

如何在reactjs中的div之间拖放?

】如何在reactjs中的div之间拖放?【英文标题】:Howtodraganddropinbetweendivsinreactjs?【发布时间】:2022-01-2023:16:15【问题描述】:我尝试使用香草HTML/jsAPI在reactjs中实现拖放功能。我几乎完成了它,但我不能将它放在现有的divs之间。... 查看详情

java示例代码_多捕获是如何在Java 7中实现的

java示例代码_多捕获是如何在Java 7中实现的 查看详情

如何在 SwiftUI (macOS) 中拖放未捆绑的图像

】如何在SwiftUI(macOS)中拖放未捆绑的图像【英文标题】:HowtodraganddropimagesnotinbundleinSwiftUI(macOS)【发布时间】:2020-05-0923:38:14【问题描述】:我正在尝试在macOS上的SwiftUI中实现拖放,我可以在其中以编程方式生成图像并将它们作为... 查看详情

Recyclerview 拖放 ontouch

...600:18:10【问题描述】:我已经使用ItemTouchHelper在recyclerview中实现拖放。它工作正常。但它只适用于长按。我需要用onTouch来做这件事ItemTouchHelper.CallbackitemTouchHelperCallback=newItemTouc 查看详情

如何在vue中实现拖拽(代码片段)

1、npmi vuedraggable2、在组件中引入importvuedraggablefrom'vuedraggable';3、<template><vuedraggableclass="wrapper"v-model="list"><transition-group><divv-for="iteminlist":key="item"class="item"><p&... 查看详情

如何在vue中实现拖拽(代码片段)

1、npmi vuedraggable2、在组件中引入importvuedraggablefrom'vuedraggable';3、<template><vuedraggableclass="wrapper"v-model="list"><transition-group><divv-for="iteminlist":key="item"class="item"><p&... 查看详情

如何在 UICollectionView 拖放期间删除“幽灵”单元格,并使移动单元格不透明?

】如何在UICollectionView拖放期间删除“幽灵”单元格,并使移动单元格不透明?【英文标题】:Howtoremove\'ghost\'cellduringUICollectionViewdrag/drop,andmakemovingcellopaque?【发布时间】:2019-09-2512:05:24【问题描述】:我正在尝试在我的UICollection... 查看详情

什么是“用鼠标移动东西”中的拖放,而不是数据传输中的拖放?

...间】:2011-10-1202:12:04【问题描述】:我正在尝试在C#和Java中实现拖放,以允许用户使用鼠标移动视觉元素,但我在Google上找 查看详情

在 UITextView 中拖放时显示文本光标

...布时间】:2018-05-0104:01:42【问题描述】:我正在我的应用中实现拖放。将应用拖放(主要是拖放)的主要屏幕之一是UITextView。我已使用以下代码向此UITextView添加了放置交互:letdropInteraction=UIDropInteraction(delegate:se 查看详情

拖放 - vb.net

...】:2011-09-1214:34:14【问题描述】:我正在Windows应用程序中实现拖放。我有主窗体(具有搜索、打开、打印等工具栏)-MdiContainer搜索时-打开一个子项-搜索表单。将文件拖放到此搜索表单上的网格中。在Grid的DragDrop事件中-调用模... 查看详情