agility
agility

Reputation: 79

Set custom cursor when dragging external file into Swing app

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

Answers (1)

Robin
Robin

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

Related Questions