Reputation: 79
I have a swing application into which I would like to import an external file by dragging the external file from windows explorer onto the application. I have this basic functionality working. However, I would like to change the default drag/drop cursor icon into an application appropriate cursor. I have not been able to change the cursor visible to the user while the mouse key is pressed and is held over the application. I have seen examples of this working if the drag and drop operation is within the same swing application. I have attempted to accomplish this using a DragGestureListener and DragSource to no avail. It seems that those methods are not called unless the drag source is within swing. Is it possible to change the drag cursor when dragging an external file into a swing application?
Please see this simplified example:
public class DnDTemplate extends JFrame {
private static final long serialVersionUID = 1L;
private JComponent thePane = null;
private Cursor dropCursor = null;
public DnDTemplate() {
super( "Drop File Here" );
thePane = (JComponent) getContentPane();
thePane.setTransferHandler( new DndTransferHandler() );
ImageIcon imageIcon = new ImageIcon( "drop_here.gif" );
Image image = imageIcon.getImage();
BufferedImage bufferedImage = new BufferedImage( 16, 16, BufferedImage.TYPE_INT_ARGB );
Graphics graphics = bufferedImage.getGraphics();
graphics.drawImage( image, 0, 0, null );
dropCursor = Toolkit.getDefaultToolkit().createCustomCursor( bufferedImage, new Point( 16, 16 ), "drop cursor" );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setSize( 300, 300 );
}
public static void main( String[] args ) {
new DnDTemplate().setVisible( true );
}
class DndTransferHandler extends TransferHandler {
private static final long serialVersionUID = 1L;
@Override
public boolean canImport( TransferHandler.TransferSupport info ) {
// This gets called repeatedly while dragged file is over frame
if ( !info.isDataFlavorSupported( DataFlavor.javaFileListFlavor ) ) {
return false;
}
// Even though this method is called at the appropriate time,
// setting the cursor here is of no consequence
info.getComponent().setCursor( dropCursor );
return true;
}
@Override
public boolean importData( TransferHandler.TransferSupport info ) {
// this gets called when file is dropped
if ( !info.isDrop() ) {
return false;
}
Transferable transferable = info.getTransferable();
String importFileName = null;
try {
List<File> fileList = (List<File>) transferable.getTransferData( DataFlavor.javaFileListFlavor );
Iterator<File> iterator = fileList.iterator();
while ( iterator.hasNext() ) {
File f = iterator.next();
importFileName = f.getAbsolutePath();
}
info.getComponent().setCursor( dropCursor );
thePane.setCursor( dropCursor );
} catch ( Exception e ) {
return false;
}
System.out.println( "Importing " + importFileName );
// Return the cursor back to the default
thePane.setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ) );
return true;
}
}
}
Upvotes: 7
Views: 2377
Reputation: 36611
Disclaimer: this should have been a comment and not an answer, but it is just too long to fit in the comments. I will delete this answer if it is completely incorrect
I did not test this but looking at the API of TransferHandler
I would suggest to take a look at the TransferHandler#getDragImage
method.
The documentation is a bit unclear on whether this image is used when the drag is initiated from the component for which the TransferHandler
is set, or also used when a drag is initiated from outside of the application and the cursor comes over the component for which the TransferHandler
is set. I found an example which seems to suggest this certainly works in Java application, but still inconclusive about drag-and-drop coming from an external application
Bug ID 4816922 suggests to use the TransferHandler#getVisualRepresentation
but it is unclear whether the bug is already fixed.
Upvotes: 1