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); } }; } }
关键修改说明
uriListFlavor类型调整:GTK3环境下,外部应用优先读取Reader类型的text/uri-list数据,替换后能更好兼容系统拖拽协议。getSourceActions重写:明确COPY动作,避免外部应用因不支持MOVE动作而拒绝拖拽请求。getTransferData返回值优化:针对text/uri-list返回StringReader,匹配新的DataFlavor定义,同时保证格式符合外部应用的解析要求。- 语法错误修复:补全
canImport方法的闭合括号,确保TransferHandler逻辑正常运行。
内容的提问来源于stack exchange,提问作者Daniel Gibby
相关产品推荐
相关产品推荐

