此问题是Custom object drag-and-drop from FX to Swing的后续问题。
我正在为 Swing 应用程序开发一个插件,该插件将 JavaFX 用于某些图形用户界面。我们添加了拖放功能以改善用户体验。首先,我们使用了一个外部 JavaFX 窗口 ( Stage
) Scene
,现在我们想通过JFXPanel
.
现在,奇怪的是,无论是在 a 中还是在 aScene
中加载完全相同的内容,拖放似乎都有很大的不同。Stage
JFXPanel
在尝试将具有自定义 MIME 类型的自定义 Java 对象(以序列化形式)从 JavaFX 应用程序拖到 Swing 应用程序时,我已经遇到了一些问题。但是,我的问题在我上面提到的问题中得到了解决。现在,在使用嵌入式 JavaFX 应用程序时,我遇到了一些新问题,所以我想问一下是否有人遇到过类似的问题或知道这种情况的解决方案。
我编写了一个 MVCE,它是一个简单的 Java 应用程序,一侧支持拖动JFXPanel
,另一侧支持拖放JPanel
:
public class MyApp {
public static final DataFormat FORMAT = new DataFormat(
// this works fine in a separate window
//"JAVA_DATAFLAVOR:application/x-my-mime-type; class=java.lang.String",
"application/x-my-mime-type; class=java.lang.String");
public static final DataFlavor FLAVOR;
static {
try {
FLAVOR = new DataFlavor("application/x-my-mime-type; class=java.lang.String");
} catch (ClassNotFoundException ex) {
throw new RuntimeException(ex);
}
}
public static void main(String[] args) {
new MyApp().run();
}
private void run() {
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(1, 2));
frame.add(buildFX());
frame.add(buildSwing());
frame.setSize(300, 300);
frame.setVisible(true);
}
private JFXPanel buildFX() {
BorderPane parent = new BorderPane();
parent.setOnDragDetected(event -> {
Dragboard dragboard = parent.startDragAndDrop(TransferMode.COPY);
ClipboardContent content = new ClipboardContent();
content.put(FORMAT, "Test");
dragboard.setContent(content);
event.consume();
});
JFXPanel panel = new JFXPanel();
panel.setScene(new Scene(parent));
return panel;
}
@SuppressWarnings("serial")
private JPanel buildSwing() {
JPanel panel = new JPanel();
panel.setBackground(Color.ORANGE);
panel.setTransferHandler(new TransferHandler() {
@Override
public boolean canImport(TransferSupport support) {
return support.isDataFlavorSupported(FLAVOR);
}
@Override
public boolean importData(TransferSupport support) {
if (!canImport(support)) return false;
try {
String data = (String) support.getTransferable().getTransferData(FLAVOR);
System.out.println(data);
return true;
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
});
return panel;
}
}
根据另一个问题的答案,Swing 必须使用前缀JAVA_DATAFLAVOR:
才能DataFormat
正确处理 MIME 类型。但是,当在 a 中使用这样的DataFormat
a JFXPanel
(在示例中禁用)时,似乎 JavaDataFlavor
在从 FX 应用程序拖动时尝试构造 a 并且无法解析带有前缀的 MIME 类型:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: failed to parse:JAVA_DATAFLAVOR:application/x-my-mime-type; class=java.lang.String
at java.awt.datatransfer.DataFlavor.<init>(Unknown Source)
at javafx.embed.swing.SwingDnD$DnDTransferable.getTransferDataFlavors(SwingDnD.java:394)
at sun.awt.datatransfer.DataTransferer.getFormatsForTransferable(Unknown Source)
at sun.awt.dnd.SunDragSourceContextPeer.startDrag(Unknown Source)
at java.awt.dnd.DragSource.startDrag(Unknown Source)
at java.awt.dnd.DragSource.startDrag(Unknown Source)
at java.awt.dnd.DragGestureEvent.startDrag(Unknown Source)
at javafx.embed.swing.SwingDnD.startDrag(SwingDnD.java:280)
at javafx.embed.swing.SwingDnD.lambda$null$66(SwingDnD.java:247)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
仅使用纯 MIME 类型,不使用前缀,拖放操作有效,我什至可以收到正确的DataFlavor
( java.awt.datatransfer.DataFlavor[mimetype=application/x-my-mime-type;representationclass=java.lang.String]
),但删除的数据始终是null
. 正如在另一个问题中看到的那样,使用带有两个分离窗口的第二种方法,我什至无法接收DataFlavor
,但现在它以某种方式工作到这个有限的点。