JDK-8146913 : [SwingNode, DND]: drag-and-drop from JTable not working, startDrag never finishes
  • Type: Bug
  • Component: javafx
  • Sub-Component: swing
  • Affected Version: 8u60
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_8
  • CPU: x86
  • Submitted: 2016-01-08
  • Updated: 2018-09-06
  • Resolved: 2017-09-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdResolved
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) Client VM (build 25.60-b23, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Windows 8 64-bit
Microsoft Windows [Version 6.3.9600]

A DESCRIPTION OF THE PROBLEM :
Very similar setup to JI-9028379

Stage-> Scene embedding SwingNode with JTable. Register a DragGestureListener and upon "dragGestureRecognized" we start "startDrag". 
This results in the FXDnD$FXDragSourceContentPeer to start its own eventdispatchLoop that is supposed to only take as long as the drag operation.

However it never returns. starting the example code (below) with parameter "swing" will run the same code without JavaFX in a JFrame. In this code drag works as expected. startDrag is entered and left once the dragoperation finishes

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
see example below

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
DragGestureEvent.startDrag should return when mouse is released and drag is finished
ACTUAL -
stays in eventdispatchloop of FX....Peer until forever

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.BorderLayout;
import java.awt.datatransfer.StringSelection;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;

import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.embed.swing.SwingNode;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class SwingFXBug1b extends Application {

	public static void main(String[] args) {
		if (args.length > 0) {
			if (args[0].equals("swing")) {
				new SwingFXBug1b().startAsSwingOnly();
			}
		} else {
			Application.launch(args);
		}
	}

	public void startAsSwingOnly() {
		JFrame frame = new JFrame();
		frame.setBounds(0, 0, 200, 200);
		JPanel panel = new JPanel();
		createContent(panel);
		frame.getContentPane().add(panel, BorderLayout.CENTER);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setTitle("Pure Swing");
		frame.pack();
		frame.setVisible(true);
	}

	@Override
	public void start(Stage stage) {

		final SwingNode swingNode = new SwingNode();
		JPanel panel = new JPanel();

		createContent(panel);
		swingNode.setContent(panel);
		BorderPane pane = new BorderPane();
		pane.setCenter(swingNode);

		stage.setTitle("Swing in JavaFX");
		stage.setScene(new Scene(pane, 250, 150));
		stage.onCloseRequestProperty().addListener(new InvalidationListener() {
			@Override
			public void invalidated(Observable observable) {
				System.exit(0);
			}
		});
		stage.show();
	}

	private void createContent(final JComponent component) {
		SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {

				DefaultTableModel tm = new DefaultTableModel();
				tm.addColumn("column-1");
				JTable table = new JTable(tm);
				tm.addRow(new String[] { "data-1" });
				tm.addRow(new String[] { "data-2" });
				tm.addRow(new String[] { "data-3" });
				tm.addRow(new String[] { "data-4" });

				// table.setTransferHandler(new TableRowTransferHandler(table));
				table.setDragEnabled(false);

				createDnDListener(table);

				component.add(table);
			}
		});
	}

	private boolean dragStarted = false;

	private void createDnDListener(JTable table) {
		DragGestureListener dgListener = new DragGestureListener() {
			@Override
			public void dragGestureRecognized(DragGestureEvent dge) {
				System.out.println("drag recognized...");
				// workaround for swingnode bug;
				if (!dragStarted) {
					dragStarted = true;
					dge.startDrag(java.awt.Cursor
							.getPredefinedCursor(java.awt.Cursor.HAND_CURSOR),
							new StringSelection("some string data"));
					dragStarted = false;
					System.out.println("drag finished");
				}
			}
		};

		DragSource dragSource = new DragSource();
		Object dragRecognizer = dragSource.createDefaultDragGestureRecognizer(
				table, DnDConstants.ACTION_COPY_OR_MOVE, dgListener);
		System.out.println(dragRecognizer);

	}
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
no workaround known