将外部文件拖动到 Swing 应用程序时设置自定义光标

发布于 2024-12-27 06:47:54 字数 2878 浏览 0 评论 0原文

我有一个 swing 应用程序,我想通过将外部文件从 Windows 资源管理器拖动到应用程序来导入外部文件。我有这个基本功能。但是,我想将默认的拖放光标图标更改为适合应用程序的光标。当鼠标键被按下并保持在应用程序上时,我无法更改用户可见的光标。如果拖放操作位于同一个 swing 应用程序中,我已经看到过这种工作的示例。我尝试使用 DragGestureListener 和 DragSource 来完成此操作,但无济于事。除非阻力源在摆动范围内,否则似乎不会调用这些方法。将外部文件拖动到 swing 应用程序时是否可以更改拖动光标?

请参阅这个简化的示例:

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;
    }

}

}

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;
    }

}

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

千紇 2025-01-03 06:47:54

免责声明:这应该是一条评论,而不是一个答案,但它太长了,不适合评论。如果它完全不正确,我将删除这个答案

我没有对此进行测试,而是查看 TransferHandler 我建议看一下 TransferHandler#getDragImage 方法。

文档有点不清楚当从设置了 TransferHandler 的组件发起拖动时是否使用此图像,或者当从应用程序和光标外部发起拖动时也使用该图像来自为其设置了 TransferHandler 的组件。我找到了一个例子 这似乎表明这在 Java 应用程序中确实有效,但对于来自外部应用程序的拖放仍然没有定论

Bug ID 4816922 建议使用 TransferHandler#getVisualRepresentation 但尚不清楚该错误是否已修复。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文