第12章:拖放与剪贴板 - 跨应用的交互

第12章:拖放与剪贴板 - 跨应用的交互


作者:步子哥 (steper@foxmail.com)


12.1 剪贴板(Clipboard)

文本的复制与粘贴

// 创建剪贴板
Clipboard clipboard = new Clipboard(display);

// 复制文本
String text = "Hello, SWT!";
TextTransfer textTransfer = TextTransfer.getInstance();
clipboard.setContents(new Object[]{text}, new Transfer[]{textTransfer});

// 粘贴文本
TextTransfer textTransfer = TextTransfer.getInstance();
String text = (String) clipboard.getContents(textTransfer);
if (text != null) {
    System.out.println("剪贴板文本:" + text);
}

// 释放剪贴板
clipboard.dispose();

费曼解释:剪贴板的原理

剪贴板 = 临时笔记本
- 你在笔记本上写下一些东西(复制文本)
- 你可以把笔记本的内容抄到其他地方(粘贴文本)
- 用完后,笔记本归还(释放剪贴板)

类比:
剪贴板 = 复印店
- 你把文件给复印店(复制文本)
- 复印店把文件复印出来
- 你可以拿复印件去别的地方(粘贴文本)
- 用完后,复印件可以丢弃(释放剪贴板)

图片的复制与粘贴

// 创建剪贴板
Clipboard clipboard = new Clipboard(display);

// 复制图片
Image image = new Image(display, "path/to/image.png");
ImageTransfer imageTransfer = ImageTransfer.getInstance();
clipboard.setContents(new Object[]{image.getImageData()}, new Transfer[]{imageTransfer});
image.dispose();

// 粘贴图片
ImageTransfer imageTransfer = ImageTransfer.getInstance();
ImageData imageData = (ImageData) clipboard.getContents(imageTransfer);
if (imageData != null) {
    Image image = new Image(display, imageData);
    // 使用图片...
    image.dispose();
}

// 释放剪贴板
clipboard.dispose();

费曼解释:图片剪贴板的工作原理

图片剪贴板 = 照片贴纸
- 你拍了一张照片(复制图片)
- 把照片贴在贴纸上(剪贴板)
- 你可以把贴纸贴到其他地方(粘贴图片)
- 用完后,贴纸可以丢弃(释放剪贴板)

类比:
图片剪贴板 = 电子相册
- 你拍了一张照片(复制图片)
- 把照片上传到相册(剪贴板)
- 你可以从相册下载照片到其他地方(粘贴图片)
- 用完后,相册的照片可以删除(释放剪贴板)

自定义数据类型

// 创建自定义数据类型
class CustomDataTransfer extends ByteArrayTransfer {
    private static final String TYPE_NAME = "custom_data";
    private static final int TYPE_ID = registerType(TYPE_NAME);
    private static CustomDataTransfer instance = new CustomDataTransfer();
    
    private CustomDataTransfer() {}
    
    public static CustomDataTransfer getInstance() {
        return instance;
    }
    
    @Override
    protected int[] getTypeIds() {
        return new int[]{TYPE_ID};
    }
    
    @Override
    protected String[] getTypeNames() {
        return new String[]{TYPE_NAME};
    }
    
    @Override
    protected void javaToNative(Object object, TransferData transferData) {
        byte[] bytes = object.toString().getBytes();
        super.javaToNative(bytes, transferData);
    }
    
    @Override
    protected Object nativeToJava(TransferData transferData) {
        byte[] bytes = (byte[]) super.nativeToJava(transferData);
        return new String(bytes);
    }
}

// 使用自定义数据类型
Clipboard clipboard = new Clipboard(display);

// 复制自定义数据
CustomDataTransfer customTransfer = CustomDataTransfer.getInstance();
String customData = "这是自定义数据";
clipboard.setContents(new Object[]{customData}, new Transfer[]{customTransfer});

// 粘贴自定义数据
CustomDataTransfer customTransfer = CustomDataTransfer.getInstance();
String customData = (String) clipboard.getContents(customTransfer);
if (customData != null) {
    System.out.println("自定义数据:" + customData);
}

// 释放剪贴板
clipboard.dispose();

费曼解释:自定义数据类型的作用

自定义数据类型 = 自定义笔记本
- 普通笔记本(文本剪贴板):只能写字
- 自定义笔记本(自定义数据类型):可以写字、画图、贴照片...
- 你需要什么类型,就创建什么类型的笔记本

类比:
自定义数据类型 = 自定义快递包装
- 普通快递包装(文本剪贴板):只能装文件
- 自定义快递包装(自定义数据类型):可以装文件、食品、电子产品...
- 你需要装什么,就创建什么类型的包装

代码示例:剪贴板

public class ClipboardExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("剪贴板示例");
        shell.setLayout(new GridLayout(2, false));
        
        // 文本区域 1
        Label label1 = new Label(shell, SWT.NONE);
        label1.setText("文本 1:");
        
        Text text1 = new Text(shell, SWT.BORDER | SWT.MULTI);
        GridData textData1 = new GridData();
        textData1.horizontalAlignment = GridData.FILL;
        textData1.verticalAlignment = GridData.FILL;
        textData1.grabExcessHorizontalSpace = true;
        textData1.grabExcessVerticalSpace = true;
        textData1.heightHint = 100;
        text1.setLayoutData(textData1);
        text1.setText("这是文本 1。\n你可以复制这段文本。");
        
        // 文本区域 2
        Label label2 = new Label(shell, SWT.NONE);
        label2.setText("文本 2:");
        
        Text text2 = new Text(shell, SWT.BORDER | SWT.MULTI);
        GridData textData2 = new GridData();
        textData2.horizontalAlignment = GridData.FILL;
        textData2.verticalAlignment = GridData.FILL;
        textData2.grabExcessHorizontalSpace = true;
        textData2.grabExcessVerticalSpace = true;
        textData2.heightHint = 100;
        text2.setLayoutData(textData2);
        
        // 按钮面板
        Composite buttonPanel = new Composite(shell, SWT.NONE);
        buttonPanel.setLayout(new FillLayout(SWT.HORIZONTAL));
        GridData buttonData = new GridData();
        buttonData.horizontalSpan = 2;
        buttonData.horizontalAlignment = GridData.FILL;
        buttonPanel.setLayoutData(buttonData);
        
        // 复制按钮
        Button copyButton = new Button(buttonPanel, SWT.PUSH);
        copyButton.setText("复制文本 1");
        copyButton.addListener(SWT.Selection, event -> {
            Clipboard clipboard = new Clipboard(display);
            try {
                String text = text1.getText();
                TextTransfer textTransfer = TextTransfer.getInstance();
                clipboard.setContents(new Object[]{text}, new Transfer[]{textTransfer});
                System.out.println("已复制到剪贴板");
            } finally {
                clipboard.dispose();
            }
        });
        
        // 粘贴按钮
        Button pasteButton = new Button(buttonPanel, SWT.PUSH);
        pasteButton.setText("粘贴到文本 2");
        pasteButton.addListener(SWT.Selection, event -> {
            Clipboard clipboard = new Clipboard(display);
            try {
                TextTransfer textTransfer = TextTransfer.getInstance();
                String text = (String) clipboard.getContents(textTransfer);
                if (text != null) {
                    text2.setText(text);
                    System.out.println("已从剪贴板粘贴");
                } else {
                    System.out.println("剪贴板为空");
                }
            } finally {
                clipboard.dispose();
            }
        });
        
        // 清空剪贴板按钮
        Button clearButton = new Button(buttonPanel, SWT.PUSH);
        clearButton.setText("清空剪贴板");
        clearButton.addListener(SWT.Selection, event -> {
            Clipboard clipboard = new Clipboard(display);
            try {
                clipboard.setContents(new Object[0], new Transfer[0]);
                System.out.println("已清空剪贴板");
            } finally {
                clipboard.dispose();
            }
        });
        
        // 查看剪贴板按钮
        Button viewButton = new Button(buttonPanel, SWT.PUSH);
        viewButton.setText("查看剪贴板");
        viewButton.addListener(SWT.Selection, event -> {
            Clipboard clipboard = new Clipboard(display);
            try {
                TextTransfer textTransfer = TextTransfer.getInstance();
                String text = (String) clipboard.getContents(textTransfer);
                if (text != null) {
                    System.out.println("剪贴板内容:" + text);
                } else {
                    System.out.println("剪贴板为空");
                }
            } finally {
                clipboard.dispose();
            }
        });
        
        shell.setBounds(100, 100, 600, 300);
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        display.dispose();
    }
}

12.2 拖放(DnD)基础

DragSource 与 DropTarget

// 拖放源:文本框
Text sourceText = new Text(shell, SWT.BORDER);
sourceText.setText("拖动我!");

DragSource dragSource = new DragSource(sourceText, DND.DROP_MOVE | DND.DROP_COPY);
dragSource.setTransfer(new Transfer[]{TextTransfer.getInstance()});

dragSource.addDragListener(new DragSourceAdapter() {
    @Override
    public void dragSetData(DragSourceEvent event) {
        if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
            event.data = sourceText.getText();
        }
    }
    
    @Override
    public void dragStart(DragSourceEvent event) {
        if (sourceText.getText().isEmpty()) {
            event.doit = false;  // 文本为空,不允许拖动
        }
    }
});

// 拖放目标:文本框
Text targetText = new Text(shell, SWT.BORDER | SWT.MULTI);

DropTarget dropTarget = new DropTarget(targetText, DND.DROP_MOVE | DND.DROP_COPY);
dropTarget.setTransfer(new Transfer[]{TextTransfer.getInstance()});

dropTarget.addDropListener(new DropTargetAdapter() {
    @Override
    public void dragEnter(DropTargetEvent event) {
        if (event.detail == DND.DROP_NONE) {
            event.detail = DND.DROP_COPY;
        }
    }
    
    @Override
    public void drop(DropTargetEvent event) {
        if (TextTransfer.getInstance().isSupportedType(event.currentDataType)) {
            String text = (String) event.data;
            targetText.setText(text);
        }
    }
});

费曼解释:DragSource 和 DropTarget 的含义

DragSource = 发货方
- 货物(数据)
- 发货人(DragSource)
- 把货物打包(dragSetData)
- 发货(拖动)

DropTarget = 收货方
- 货物(数据)
- 收货人(DropTarget)
- 接收货物(drop)
- 卸货(获取数据)

类比:
DragSource = 递纸条
- 你写了一张纸条(数据)
- 你是发送方(DragSource)
- 你把纸条递给同学(拖动)

DropTarget = 接纸条
- 同学接了你的纸条(数据)
- 同学是接收方(DropTarget)
- 同学阅读纸条(drop)

拖放的类型:文本、文件、自定义数据

// 文本拖放
TextTransfer textTransfer = TextTransfer.getInstance();
dragSource.setTransfer(new Transfer[]{textTransfer});
dropTarget.setTransfer(new Transfer[]{textTransfer});

// 文件拖放
FileTransfer fileTransfer = FileTransfer.getInstance();
dragSource.setTransfer(new Transfer[]{fileTransfer});
dropTarget.setTransfer(new Transfer[]{fileTransfer});

// 自定义数据拖放
CustomDataTransfer customTransfer = CustomDataTransfer.getInstance();
dragSource.setTransfer(new Transfer[]{customTransfer});
dropTarget.setTransfer(new Transfer[]{customTransfer});

// 多种类型拖放
dragSource.setTransfer(new Transfer[]{TextTransfer.getInstance(), FileTransfer.getInstance()});
dropTarget.setTransfer(new Transfer[]{TextTransfer.getInstance(), FileTransfer.getInstance()});

费曼解释:多种拖放类型的作用

多种拖放类型 = 多种快递服务
- 文本快递(TextTransfer):运送文字
- 文件快递(FileTransfer):运送文件
- 自定义快递(CustomDataTransfer):运送自定义数据

类比:
多种拖放类型 = 餐厅的外卖
- 文字外卖(TextTransfer):菜单文字
- 文件外卖(FileTransfer):菜品图片
- 自定义外卖(CustomDataTransfer):特殊菜品

代码示例:文本拖放

public class TextDragDropExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("文本拖放示例");
        shell.setLayout(new GridLayout(2, false));
        
        // 拖放源
        Label sourceLabel = new Label(shell, SWT.NONE);
        sourceLabel.setText("拖放源:");
        
        Text sourceText = new Text(shell, SWT.BORDER);
        sourceText.setText("拖动这段文本!");
        GridData sourceData = new GridData();
        sourceData.horizontalAlignment = GridData.FILL;
        sourceText.setLayoutData(sourceData);
        
        // 设置 DragSource
        DragSource dragSource = new DragSource(sourceText, DND.DROP_MOVE | DND.DROP_COPY);
        dragSource.setTransfer(new Transfer[]{TextTransfer.getInstance()});
        
        dragSource.addDragListener(new DragSourceAdapter() {
            @Override
            public void dragSetData(DragSourceEvent event) {
                if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
                    event.data = sourceText.getText();
                }
            }
            
            @Override
            public void dragStart(DragSourceEvent event) {
                if (sourceText.getText().isEmpty()) {
                    event.doit = false;
                }
            }
        });
        
        // 拖放目标
        Label targetLabel = new Label(shell, SWT.NONE);
        targetLabel.setText("拖放目标:");
        
        Text targetText = new Text(shell, SWT.BORDER | SWT.MULTI);
        GridData targetData = new GridData();
        targetData.horizontalAlignment = GridData.FILL;
        targetData.verticalAlignment = GridData.FILL;
        targetData.grabExcessHorizontalSpace = true;
        targetData.grabExcessVerticalSpace = true;
        targetData.heightHint = 100;
        targetText.setLayoutData(targetData);
        
        // 设置 DropTarget
        DropTarget dropTarget = new DropTarget(targetText, DND.DROP_MOVE | DND.DROP_COPY);
        dropTarget.setTransfer(new Transfer[]{TextTransfer.getInstance()});
        
        dropTarget.addDropListener(new DropTargetAdapter() {
            @Override
            public void dragEnter(DropTargetEvent event) {
                if (event.detail == DND.DROP_NONE) {
                    event.detail = DND.DROP_COPY;
                }
            }
            
            @Override
            public void drop(DropTargetEvent event) {
                if (TextTransfer.getInstance().isSupportedType(event.currentDataType)) {
                    String text = (String) event.data;
                    targetText.setText(text);
                    System.out.println("拖放成功:" + text);
                }
            }
        });
        
        // 清空按钮
        Button clearButton = new Button(shell, SWT.PUSH);
        clearButton.setText("清空目标");
        clearButton.addListener(SWT.Selection, event -> {
            targetText.setText("");
        });
        
        shell.setBounds(100, 100, 500, 200);
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        display.dispose();
    }
}

12.3 拖放的事件监听

DragStartEvent

dragSource.addDragListener(new DragSourceAdapter() {
    @Override
    public void dragStart(DragSourceEvent event) {
        System.out.println("拖动开始");
        
        // 检查是否允许拖动
        if (!allowDrag()) {
            event.doit = false;  // 不允许拖动
        }
    }
});

费曼解释:DragStartEvent 的含义

DragStartEvent = 发货检查
- 你要发货(拖动开始)
- 快递员检查:货物是否允许发货(DragStartEvent)
- 不允许发货 = 检查未通过(event.doit = false)
- 允许发货 = 检查通过(event.doit = true)

类比:
DragStartEvent = 纸条检查
- 你要递纸条(拖动开始)
- 老师检查:纸条内容是否允许传递(DragStartEvent)
- 不允许传递 = 检查未通过(event.doit = false)
- 允许传递 = 检查通过(event.doit = true)

DragEnterEvent、DragOverEvent

dropTarget.addDropListener(new DropTargetAdapter() {
    @Override
    public void dragEnter(DropTargetEvent event) {
        System.out.println("拖动进入目标区域");
        
        // 设置默认操作
        if (event.detail == DND.DROP_NONE) {
            event.detail = DND.DROP_COPY;
        }
    }
    
    @Override
    public void dragOver(DropTargetEvent event) {
        System.out.println("拖动在目标区域上方");
        
        // 可以根据位置改变操作
        if (event.y < 50) {
            event.detail = DND.DROP_MOVE;  // 上半部分:移动
        } else {
            event.detail = DND.DROP_COPY;  // 下半部分:复制
        }
    }
    
    @Override
    public void dragLeave(DropTargetEvent event) {
        System.out.println("拖动离开目标区域");
    }
});

费曼解释:这些事件的含义

dragEnter = 快递到达目的地
- 快递车到达了目的地(拖动进入目标区域)
- 通知收货人:快递到了(dragEnter)

dragOver = 快递在目的地上方
- 快递车在目的地上方行驶(拖动在目标区域上方)
- 收货人看到快递车,准备接收(dragOver)

dragLeave = 快递离开目的地
- 快递车离开了目的地(拖动离开目标区域)
- 收货人知道:快递走了(dragLeave)

类比:
dragEnter = 纸条到达同学那里
- 你把纸条递给同学(拖动进入目标区域)
- 同学看到纸条:收到了(dragEnter)

dragOver = 纸条在同学上方
- 纸条在同学上方晃动(拖动在目标区域上方)
- 同学准备接纸条(dragOver)

dragLeave = 纸条离开同学那里
- 纸条离开了同学那里(拖动离开目标区域)
- 同学知道:纸条走了(dragLeave)

DropEvent

dropTarget.addDropListener(new DropTargetAdapter() {
    @Override
    public void drop(DropTargetEvent event) {
        System.out.println("放下数据");
        
        // 获取数据
        if (TextTransfer.getInstance().isSupportedType(event.currentDataType)) {
            String text = (String) event.data;
            System.out.println("拖放的数据:" + text);
        }
    }
    
    @Override
    public void dropAccept(DropTargetEvent event) {
        System.out.println("接受拖放");
        
        // 检查是否接受拖放
        if (!acceptDrop()) {
            event.detail = DND.DROP_NONE;  // 不接受拖放
        }
    }
});

费曼解释:DropEvent 的含义

drop = 收货
- 快递员把货物递给收货人(drop)
- 收货人签字确认(dropAccept)
- 收货人检查货物是否接收(dropAccept)

类比:
drop = 接纸条
- 你把纸条递给同学(drop)
- 同学决定是否接受(dropAccept)
- 同学检查纸条内容是否允许接收(dropAccept)

代码示例:拖放事件监听

public class DragDropEventsExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("拖放事件监听");
        shell.setLayout(new GridLayout(2, false));
        
        // 拖放源
        Text sourceText = new Text(shell, SWT.BORDER);
        sourceText.setText("拖动这段文本,查看事件!");
        GridData sourceData = new GridData();
        sourceData.horizontalAlignment = GridData.FILL;
        sourceText.setLayoutData(sourceData);
        
        DragSource dragSource = new DragSource(sourceText, DND.DROP_MOVE | DND.DROP_COPY);
        dragSource.setTransfer(new Transfer[]{TextTransfer.getInstance()});
        
        dragSource.addDragListener(new DragSourceAdapter() {
            @Override
            public void dragStart(DragSourceEvent event) {
                System.out.println("dragStart:拖动开始");
                
                if (sourceText.getText().isEmpty()) {
                    event.doit = false;
                    System.out.println("dragStart:不允许拖动(文本为空)");
                }
            }
            
            @Override
            public void dragSetData(DragSourceEvent event) {
                System.out.println("dragSetData:设置数据");
                
                if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
                    event.data = sourceText.getText();
                    System.out.println("dragSetData:数据 = " + sourceText.getText());
                }
            }
            
            @Override
            public void dragFinished(DragSourceEvent event) {
                System.out.println("dragFinished:拖动完成");
                
                if (event.detail == DND.DROP_MOVE) {
                    sourceText.setText("");  // 移动:清空源文本
                }
            }
        });
        
        // 拖放目标
        Text targetText = new Text(shell, SWT.BORDER | SWT.MULTI);
        GridData targetData = new GridData();
        targetData.horizontalAlignment = GridData.FILL;
        targetData.verticalAlignment = GridData.FILL;
        targetData.grabExcessHorizontalSpace = true;
        targetData.grabExcessVerticalSpace = true;
        targetData.heightHint = 150;
        targetText.setLayoutData(targetData);
        
        DropTarget dropTarget = new DropTarget(targetText, DND.DROP_MOVE | DND.DROP_COPY);
        dropTarget.setTransfer(new Transfer[]{TextTransfer.getInstance()});
        
        dropTarget.addDropListener(new DropTargetAdapter() {
            @Override
            public void dragEnter(DropTargetEvent event) {
                System.out.println("dragEnter:拖动进入目标区域");
                
                if (event.detail == DND.DROP_NONE) {
                    event.detail = DND.DROP_COPY;
                }
            }
            
            @Override
            public void dragOver(DropTargetEvent event) {
                System.out.println("dragOver:拖动在目标区域上方,位置 = (" + event.x + ", " + event.y + ")");
            }
            
            @Override
            public void dragLeave(DropTargetEvent event) {
                System.out.println("dragLeave:拖动离开目标区域");
            }
            
            @Override
            public void dropAccept(DropTargetEvent event) {
                System.out.println("dropAccept:接受拖放");
            }
            
            @Override
            public void drop(DropTargetEvent event) {
                System.out.println("drop:放下数据");
                
                if (TextTransfer.getInstance().isSupportedType(event.currentDataType)) {
                    String text = (String) event.data;
                    targetText.setText(text);
                    System.out.println("drop:数据 = " + text);
                }
            }
        });
        
        shell.setBounds(100, 100, 600, 300);
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        display.dispose();
    }
}

12.4 实战案例:拖放文件到应用

public class FileDragDropExample {
    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("拖放文件到应用");
        shell.setLayout(new GridLayout(1, false));
        
        // 拖放目标
        Label label = new Label(shell, SWT.WRAP);
        label.setText("从文件管理器拖动文件到这里:");
        label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        
        Text fileText = new Text(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL);
        GridData textData = new GridData();
        textData.horizontalAlignment = GridData.FILL;
        textData.verticalAlignment = GridData.FILL;
        textData.grabExcessHorizontalSpace = true;
        textData.grabExcessVerticalSpace = true;
        textData.heightHint = 200;
        fileText.setLayoutData(textData);
        
        // 设置 DropTarget
        DropTarget dropTarget = new DropTarget(fileText, DND.DROP_COPY);
        dropTarget.setTransfer(new Transfer[]{FileTransfer.getInstance()});
        
        dropTarget.addDropListener(new DropTargetAdapter() {
            @Override
            public void dragEnter(DropTargetEvent event) {
                if (event.detail == DND.DROP_NONE) {
                    event.detail = DND.DROP_COPY;
                }
            }
            
            @Override
            public void drop(DropTargetEvent event) {
                if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
                    String[] fileNames = (String[]) event.data;
                    StringBuilder sb = new StringBuilder();
                    
                    for (String fileName : fileNames) {
                        File file = new File(fileName);
                        sb.append("文件名:").append(file.getName()).append("\n");
                        sb.append("路径:").append(file.getAbsolutePath()).append("\n");
                        sb.append("大小:").append(file.length()).append(" 字节\n");
                        sb.append("是否是目录:").append(file.isDirectory()).append("\n\n");
                    }
                    
                    fileText.setText(sb.toString());
                    System.out.println("拖放了 " + fileNames.length + " 个文件");
                }
            }
        });
        
        shell.setBounds(100, 100, 600, 400);
        shell.open();
        
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        
        display.dispose();
    }
}

费曼解释:文件拖放的应用场景

文件拖放 = 把文件从文件夹拖到应用
- 文件管理器 = 文件夹
- 应用 = 另一个文件夹
- 拖放 = 把文件从一个文件夹搬到另一个文件夹

类比:
文件拖放 = 搬家
- 旧家(文件管理器)
- 新家(应用)
- 搬家(拖放)
- 把家具(文件)从旧家搬到新家

12.5 本章小结

拖放与剪贴板总结

概念作用类比
Clipboard临时存储数据临时笔记本
TextTransfer文本数据类型文字快递
FileTransfer文件数据类型文件快递
DragSource拖放源发货方
DropTarget拖放目标收货方
dragStart拖动开始发货检查
drop放下数据收货

费曼测试:你能解释清楚吗?

  1. 剪贴板的作用?

- 临时存储数据,可以在不同应用之间复制粘贴

  1. DragSource 和 DropTarget 的区别?

- DragSource:拖放源,发送数据 - DropTarget:拖放目标,接收数据

  1. 拖放事件的含义?

- dragStart:拖动开始 - dragEnter:进入目标区域 - dragOver:在目标区域上方 - drop:放下数据

  1. 如何支持多种拖放类型?

- 使用 Transfer 数组,如 new Transfer[]{TextTransfer.getInstance(), FileTransfer.getInstance()}

下一章预告

现在你已经掌握了拖放与剪贴板,
可以让应用与其他应用交互,
提升用户体验。

下一章,我们将学习 SWT 与操作系统的深度集成,
让应用更好地利用系统功能,
比如调用系统浏览器、系统托盘等。

练习题:

  1. 创建一个文本框,实现文本的复制粘贴功能。
  2. 创建两个文本框,实现从第一个文本框拖动文本到第二个文本框。
  3. 创建一个应用,支持从文件管理器拖放文件到应用,并显示文件信息。

(提示:拖放使用 DragSource 和 DropTarget,剪贴板使用 Clipboard)

← 返回目录