为啥我不能将文件从 Windows 中的 CD 拖放到 Eclipse / SWT Drop Target

Posted

技术标签:

【中文标题】为啥我不能将文件从 Windows 中的 CD 拖放到 Eclipse / SWT Drop Target【英文标题】:Why can't I drop files on to Eclipse / SWT Drop Target from a CD in windows为什么我不能将文件从 Windows 中的 CD 拖放到 Eclipse / SWT Drop Target 【发布时间】:2012-10-06 10:50:26 【问题描述】:

在我的 Eclipse RCP 应用程序中,我有一个 TreeViewer,它是文件的放置目标,它在大多数情况下都可以正常工作,但是当我尝试将存储在 CD ROM 上的文件从 Windows 资源管理器拖动到节点时,指示放置的图标are allowed 不会改变,而 drop 什么都不做。

由于人们似乎对我的问题感到困惑,这里有一个更详细的解释:

执行下面的代码(由 Baz 提供)时,我可以将文件拖放到文本框中,当我从机器上的大多数位置拖动文件时,窗口显示如下 ->

光标表示我可以放下,当我松开鼠标时会调用drop(DropTargetEvent event)方法。

现在,当我做同样的事情,但从资源管理器中获取一个位于我的光驱 DVD 上的文件时,它看起来像这样:

表示不允许放置,当我释放鼠标时,drop(DropTargetEvent event) 方法不会被调用。

还值得注意的是,我可以将相同的 DVD 文件放入 eclipse 导航器中的文件夹中,这表明这不是特定于机器的问题,在 eclipse 树中一定有不同的东西允许它但是我看不到。

package widgets;

import java.util.Arrays;

import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.PluginTransfer;

public class SourceTest 
    public static void main(String[] args) 
        final Display display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new GridLayout(1,false));

        final Text text = new Text(shell, SWT.BORDER);
        text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));

        DropTarget dt = new DropTarget(text, DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK);
        dt.setTransfer(new Transfer[]  FileTransfer.getInstance(), PluginTransfer.getInstance() );
        dt.addDropListener(new DropTargetAdapter() 
            public void drop(DropTargetEvent event) 
                String fileList[] = null;
                FileTransfer ft = FileTransfer.getInstance();
                if (ft.isSupportedType(event.currentDataType)) 
                    fileList = (String[]) event.data;
                
                System.out.println(Arrays.toString(fileList));
            
        );

        shell.setSize(300, 100);
        shell.open();

        while (!shell.isDisposed()) 
            if (!display.readAndDispatch())
                display.sleep();
        
        display.dispose();
    


【问题讨论】:

您是否检查过validateDrop 方法中的transferType 是否与从HDD 删除时的不同? 它们是 TransferData 对象,在结构上似乎没有任何重大差异,但对于 ROM 文件,操作似乎始终为 16,而对于工作的文件,操作结束时变为 2一个节点,如果不是,则为 16,这向我表明该节点没有注册为被拖动对象的可行目标。对 validateDrop 的调用是很奇怪的,即使它实际上并没有允许您执行它的意图。 基于名称 **validate**Drop() 这是有道理的。会研究一下。也许我会找到解决办法。 这个名字听起来好像应该被删除,但在这种情况下,即使它返回 true,框架也不会尝试执行删除,因为它已经确定目标无效。提前感谢您的时间 Baz 【参考方案1】:

当来自 CDROM 设备时,似乎并非所有可能的 DND 操作都受支持。因此,您需要在 DropTargetAdapter 上实现更多方法,以便在进行中修改 Drop 操作以缩小实际执行的操作范围,以便操作系统不会阻止 drop。

我以你的例子为例,只是对DropTargetAdapter做了一点小改动

    @Override
    public void dropAccept( DropTargetEvent event )
    
        Object object = FileTransfer.getInstance().nativeToJava( event.currentDataType );
        if( object instanceof String[] )
        
            String[] strs = (String[]) object;
            System.out.println("dropAccept " + strs[0]);
            event.detail = DND.DROP_COPY;
        
        event.detail = DND.DROP_COPY;
    
    @Override
    public void dragEnter( DropTargetEvent event )
    
        event.detail = DND.DROP_COPY;
    

【讨论】:

我的好伙计做得很好。所以本质上覆盖细节总是看起来好像它是一个副本?这不会导致其他事件类型出现奇怪的行为吗? 因此您可以添加一些代码以便在“修改”此事件时更有选择性。我将在我的答案中添加一些代码,以显示您如何“嗅探”将要删除的内容的位置,并确定何时修改以及何时不理会。​​span> 谢谢,我看看能否在 Eclipse 树中找到等价物。【参考方案2】:

我认为更新你的问题澄清了问题是什么。

您的放置目标使用DND_MOVE 作为标志。 由于我们无法删除 DVD 等只读媒体中的文件,

无论接收者的决定是否正确,发送者(在本例中为 OS 的 shell)都会拒绝 DND 通信。

您的屏幕截图显示正在移动 DND 反馈不是复制

dropAccept()给你最后一次修改通讯请求的机会, 请谨慎使用,因为每个传输类型可以存在多个放置目标侦听器。为了支持这种情况,TreeViewer 的 DND API 与 SWT 的略有不同。

【讨论】:

【参考方案3】:

DND 并不像你想象的那样工作。

考虑从网络下载一些文件。 当您验证下载时,没有实际的文件内容,但您有一个网络资源的唯一 URL

同样,当您验证 drop 操作时,您无法知道实际数据,因为在您接受 drop 操作之前,没有 没有建立连接。在验证阶段您唯一能知道的是传输类型

因此,您只能根据内容类型验证 drop,而不是“实际内容”

典型的验证码是:

public boolean validateDrop(...)
    return FileTransfer.getInstance().isSupportedType(transferData);

在您接受“TransferData”后,传输将从连接中检索实际数据。

所以请记住,“TransferData”与实际数据不同。

FileTransferString 数组的形式检索文件,其中包含每个文件的绝对路径,而不是 Java File 对象。

P.S.:剪贴板的工作方式相同。

【讨论】:

谢谢我知道这一切。那你建议问题的答案是什么? 我自己对此投了反对票,这肯定是一个详细的信息,但它不是答案,jeeyul 认为我不明白如何使用拖放,只是希望文件能够自动移动。事实并非如此。

以上是关于为啥我不能将文件从 Windows 中的 CD 拖放到 Eclipse / SWT Drop Target的主要内容,如果未能解决你的问题,请参考以下文章

为啥我安装了TOOLS不能拖放文件到虚拟机

我虚拟机里面装了ubuntu的desktop版本,请问为啥我windows里的文件拖不进去虚拟机?

VMware tools 安装成功后,文件可以从虚拟机拖出去,但是拖不进来,为啥?

为啥图片拖不进对话框,拖的话,会从网页上打开,复制粘贴都没用

从 Java Swing 应用程序拖放到 Windows 资源管理器

将大型虚拟文件从 C# 拖放到 Windows 资源管理器