You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu 20.04.4 LTS下Java Swing向外部应用拖拽失效问题排查

Ubuntu升级后Java Swing应用外部拖拽失效的解决方法

问题背景

未修改代码的情况下,Ubuntu升级到20.04.4 LTS后,Java Swing应用内部拖拽功能正常,但向Firefox/Chrome浏览器、Dolphin文件管理器等外部应用拖拽文件时,拖拽启动图标显示正常,但拖拽到外部应用区域会出现红色禁止图标,松开鼠标后应用无任何响应。当前拖拽实现代码如下:

public static DataFlavor uriListFlavor; // initialized elsewhere as new DataFlavor("text/uri-list;class=java.lang.String");
JTable docsTable; // initialized elsewhere

docsTable.setTransferHandler(new DocTransferHandler());
//etc.

public static class DocTransferHandler extends TransferHandler {

    DocTransferHandler() {
    }

    @Override
    protected Transferable createTransferable(JComponent component) {
      ArrayList<File> files = new ArrayList<>();
      if (component instanceof JTable) {
        JTable table = (JTable)component;
        int[] rows = table.getSelectedRows();
        for (int row : rows) {
          String filePath = String.valueOf(table.getModel().getValueAt(row, FILE_PATH_COLUMN));
          String fileName = String.valueOf(table.getModel().getValueAt(row, FILE_NAME_COLUMN));
          files.add(new File(filePath+"/"+fileName));
       }
      }
      return new Transferable() {
        @Override
        public DataFlavor[] getTransferDataFlavors() {
          DataFlavor[] flavors = new DataFlavor[2];
          flavors[0] = DataFlavor.javaFileListFlavor;
          flavors[1] = uriListFlavor;
          return flavors;
        }

        @Override
        public boolean canImport(TransferSupport support) {
          return (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor) || support.isDataFlavorSupported(uriListFlavor);
        }

        @Override
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
          if (flavor.equals(CaseManagedDocs.uriListFlavor)) {
            String uriList = "";
            for (File file : files) {
              uriList += file.toURI() + System.lineSeparator();
            }
            return uriList;
          } else if (flavor.equals(DataFlavor.javaFileListFlavor)) {
            return files;
          }
          throw new UnsupportedFlavorException(flavor);
        }
      };
    }
}

需要调整的代码部分

  • 修正uriListFlavor的MIME类型定义:Ubuntu 20.04的GTK3拖拽框架对text/uri-list的格式要求更严格,原定义的class=java.lang.String无法被外部应用正常识别,需改为class=java.io.Reader。
  • 修复canImport方法的语法错误:原代码缺少闭合括号,会导致TransferHandler逻辑异常,影响外部拖拽交互。
  • 优化text/uri-list的生成格式:确保URI以file://开头,每个URI单独一行,移除末尾多余换行符,避免部分外部应用因格式问题拒绝接收。
  • 重写getSourceActions方法:显式指定仅支持COPY动作,外部应用通常只接受该操作,默认的COPY_OR_MOVE会导致兼容性问题。

修改后的完整代码示例

public static DataFlavor uriListFlavor; 
// 初始化标准text/uri-list DataFlavor
static {
    try {
        uriListFlavor = new DataFlavor("text/uri-list;class=java.io.Reader");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

JTable docsTable; // 已在其他位置初始化

docsTable.setTransferHandler(new DocTransferHandler());

public static class DocTransferHandler extends TransferHandler {

    public DocTransferHandler() {
    }

    // 明确指定拖拽动作仅支持COPY
    @Override
    public int getSourceActions(JComponent c) {
        return COPY;
    }

    @Override
    protected Transferable createTransferable(JComponent component) {
        ArrayList<File> files = new ArrayList<>();
        if (component instanceof JTable) {
            JTable table = (JTable) component;
            int[] rows = table.getSelectedRows();
            for (int row : rows) {
                String filePath = String.valueOf(table.getModel().getValueAt(row, FILE_PATH_COLUMN));
                String fileName = String.valueOf(table.getModel().getValueAt(row, FILE_NAME_COLUMN));
                files.add(new File(filePath + "/" + fileName));
            }
        }

        return new Transferable() {
            @Override
            public DataFlavor[] getTransferDataFlavors() {
                return new DataFlavor[]{DataFlavor.javaFileListFlavor, uriListFlavor};
            }

            @Override
            public boolean isDataFlavorSupported(DataFlavor flavor) {
                return flavor.equals(DataFlavor.javaFileListFlavor) || flavor.equals(uriListFlavor);
            }

            // 修正语法错误,补全闭合括号
            @Override
            public boolean canImport(TransferSupport support) {
                return support.isDataFlavorSupported(DataFlavor.javaFileListFlavor) 
                        || support.isDataFlavorSupported(uriListFlavor);
            }

            @Override
            public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
                if (flavor.equals(uriListFlavor)) {
                    StringBuilder uriList = new StringBuilder();
                    for (File file : files) {
                        uriList.append(file.toURI().toString()).append("\r\n");
                    }
                    // 返回Reader类型,匹配修正后的DataFlavor要求,同时修剪多余换行符
                    return new StringReader(uriList.toString().trim());
                } else if (flavor.equals(DataFlavor.javaFileListFlavor)) {
                    return files;
                }
                throw new UnsupportedFlavorException(flavor);
            }
        };
    }
}

关键修改说明

  1. uriListFlavor类型调整:GTK3环境下,外部应用优先读取Reader类型的text/uri-list数据,替换后能更好兼容系统拖拽协议。
  2. getSourceActions重写:明确COPY动作,避免外部应用因不支持MOVE动作而拒绝拖拽请求。
  3. getTransferData返回值优化:针对text/uri-list返回StringReader,匹配新的DataFlavor定义,同时保证格式符合外部应用的解析要求。
  4. 语法错误修复:补全canImport方法的闭合括号,确保TransferHandler逻辑正常运行。

内容的提问来源于stack exchange,提问作者Daniel Gibby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 11:39:47