将.lnk文件拖到Windows 10任务栏

时间:2019-05-18 18:33:22

标签: java windows drag-and-drop swt

如何使用Java和SWT将.lnk文件成功拖动到Windows 10任务栏(“固定到任务栏”)?我已经尝试过下面的代码(拖动标签的内容),但是无论我使用什么操作常量,它都会在Windows 10任务栏上显示不允许拖动的光标。

import org.eclipse.swt.*;
import org.eclipse.swt.dnd.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class DragTest {

    public static void main(String[] args) {
        final Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());
        final Label label = new Label(shell, SWT.BORDER);
        label.setText("Start drag from here");

        final Transfer[] types = new Transfer[] {FileTransfer.getInstance()};
        final int operations = DND.DROP_LINK; // DND.DROP_COPY or DND.DROP_MOVE

        final DragSource source = new DragSource(label, operations);
        source.setTransfer(types);
        source.addListener(DND.DragSetData, 
                           event -> event.data = new String[] { 
                                "C:\\ThunderbirdPortable\\ThunderbirdPortable - Shortcut.lnk"
                           });

        shell.setSize(200, 200);
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }
}

请注意,从Windows资源管理器中拖动文件效果很好,因此文件正确。

1 个答案:

答案 0 :(得分:2)

目前,SWT的传输类型均不能用于放置在任务栏上。问题在于FileTransfer使用CF_HDROP作为传输数据类型,而任务栏期望使用CFSTR_SHELLIDLIST

另请参阅类似的chromium bug report和此SWT bug report

为了表明SWT通常可以放到任务栏,我修改了您的示例。

import org.eclipse.swt.*;
import org.eclipse.swt.dnd.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class DragTransferTest {

    public static void main(String[] args) {
        final Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());
        final Label label = new Label(shell, SWT.BORDER);
        label.setText("Drop file here to start");

        final Transfer[] types = new Transfer[] { new ByteArrayTransfer() {

            byte[] lastDrop;

            @Override
            protected Object nativeToJava(TransferData transferData) {
                byte[] data = (byte[]) super.nativeToJava(transferData);
                lastDrop = data;
                return null;
            }

            @Override
            protected void javaToNative(Object object, TransferData transferData) {
                if (lastDrop == null) {
                    DND.error(DND.ERROR_INVALID_DATA);
                }
                super.javaToNative(lastDrop, transferData);
            };

            @Override
            protected String[] getTypeNames() {
                return new String[] { "Shell IDList Array" };
            }

            @Override
            protected int[] getTypeIds() {
                return new int[] { registerType("Shell IDList Array") };
            }
        } };
        final int operations = DND.DROP_LINK | DND.DROP_COPY | DND.DROP_MOVE;

        final DragSource source = new DragSource(label, operations);
        source.setTransfer(types);

        DropTarget target = new DropTarget(label, -1);
        target.setTransfer(types);

        shell.setSize(200, 200);
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }
}

如果将文件(.lnk或其他类型)拖放到此示例上,然后从该文件拖到任务栏,则固定应该起作用。

因此,最后,您唯一需要做的就是用CFSTR_SHELLIDLIST实现新的Transfer,它以IDAITEMLISTS的形式提供数据。

小更新: 我在Windows 7上对此进行了测试,但是无论出于何种原因,传输类型ID在Windows 10上都是另一个。因此,在上面的示例中,您需要将Windows 7的ID 49287替换为Windows 10的49336。您可以使用SWT Snippet 83轻松检查这些ID。

here所述,获取类型ID的正确方法是使用RegisterClipboardFormat函数。