使用Java实现带有一定透明度的光标

7
我有一个35x40像素的.png图片,我想在Swing应用程序中使用它作为自定义光标。该图像具有发光效果,因此包含alpha透明度值。问题是,当我尝试使用传统方法使用Toolkit生成自定义光标时,我会得到黑色像素,而不是alpha透明度值。
这是我用作光标的图片:https://dl.dropbox.com/u/1186703/cursor.png 以下是我的代码:
public static void main(String[] args) throws IOException {

     new Sandbox().gui();

}
private Cursor cursor;

private Toolkit kit;

private Image cursorImage;

public void gui() {

    kit = Toolkit.getDefaultToolkit();
    cursorImage = kit.createImage(getClass().getResource(
            "/aurora/V1/resources/cursor.png"));

    cursor = Toolkit.getDefaultToolkit().createCustomCursor(
            cursorImage, new Point(0, 0), "CustomCursor");

    setSize(800, 800);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setVisible(true);
    setCursor(cursor);
}

这是当前的结果:

result

编辑 看起来这种方法在跨平台时效果不佳,例如 Windows LAF 不支持半透明。因此,我正在寻找任何解决方案,以在 Windows 上使其正常工作,假设该实现在 Mac OSX 上可行,我可以根据应用程序运行的操作系统指定要使用哪个实现。


我实际上认为这是不可能的,而且在多个平台上也肯定不可能。如果您知道您的操作系统可以支持这样的操作,您可能需要使用本地方法来实现它。 - MadProgrammer
如果这个程序在Mac OSX上能够运行,那么我需要采取哪些本地方法才能使其在Windows上运行? - Sammy Guergachi
我尝试使用JNA库,但失败了:我无法将HCURSOR与窗口关联起来。 - Alexey Ivanov
Java在Windows上不支持部分透明。您可以使用JNA/JNI加载光标,并通过SetClassLong将其与JFrame窗口类[WNDCLASSEX](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633577(v=vs.85).aspx)关联,但对JFrame上的光标没有影响。然而,这种方法在Win32 API中完美运行。 - Alexey Ivanov
4个回答

7

您的代码和光标图像实际上在MacOS X 10.7.5(jdk 1.6.0_31)上产生了所需的结果,带有半透明蓝色边框。但是我注意到在此答案中有一条注释,指出默认的Windows外观不支持部分透明。


6
你遇到的问题与Cursor类有关,它(在Windows下)没有考虑图像的透明度值。
这绝不是一个“真正”的解决方案,更多地是“捏造”结果...
public class TestMouseCursor {

    public static void main(String[] args) {
        new TestMouseCursor();
    }

    public TestMouseCursor() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new MouseCursorPane());
                frame.setSize(400, 400);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MouseCursorPane extends JPanel {

        private BufferedImage cursorImage;
        private Toolkit kit;

        public MouseCursorPane() {
            try {
                kit = Toolkit.getDefaultToolkit();
                cursorImage = ImageIO.read(getClass().getResource("/cursor02.png"));
                for (int i = 0; i < cursorImage.getHeight(); i++) {
                    int[] rgb = cursorImage.getRGB(0, i, cursorImage.getWidth(), 1, null, 0, cursorImage.getWidth() * 4);
                    for (int j = 0; j < rgb.length; j++) {
                        int alpha = (rgb[j] >> 24) & 255;
                        if (alpha < 128) {
                            alpha = 0;
                        } else {
                            alpha = 255;
                        }
                        rgb[j] &= 0x00ffffff;
                        rgb[j] = (alpha << 24) | rgb[j];
                    }
                    cursorImage.setRGB(0, i, cursorImage.getWidth(), 1, rgb, 0,
                            cursorImage.getWidth() * 4);
                }
                Cursor cursor = Toolkit.getDefaultToolkit().createCustomCursor(
                        cursorImage, new Point(0, 0), "CustomCursor");

                setCursor(cursor);

            } catch (Exception exp) {
                exp.printStackTrace();
            }
        }
    }
}

我从这里得到了灵感


它部分地起作用,它删除了所有透明度值,即使部分透明度也不存在,因此蓝色的发光完全被移除了。比以前好,但不幸的是对于我所寻找的还不够好。 - Sammy Guergachi
我同意,但根据我所读的所有内容,这是我认为在有人修复光标之前,你能得到的最接近的东西。 - MadProgrammer

2
如果你非常迫切地需要透明光标,无论后果如何,你可以使用JNI并使用Win32 API手动设置光标。自Windows XP以来,支持alpha透明光标,所以这应该没问题。
但是您会失去平台独立性。而且根据Windows的设置,该特定用户的alpha混合可能已被关闭。

为什么会失去平台独立性呢?如果是Windows,只需进行特殊情况的判断即可。在Mac上,alpha通常都可以正常工作,因此不需要调用此代码。此外,如何使用JNI来使用Windows 32 API设置光标呢?有什么链接可以帮助我入门吗?(对于这个问题的追问十分抱歉) - Perry Monschau

2
一个替代方法是伪造一个光标。
看看Alexander Potochkin的Well Behaved GlassPane
特别是运行示例代码,选择选项>GlassPane is Visible选项>Final GlassPane
从这里开始,加载一个完全透明的光标图像,然后在玻璃面板上绘制一个透明度混合的正确光标。

问题在于我使用了许多不同的鼠标监听器,这种方法似乎会导致很多奇怪的行为,比如按钮不显示悬停状态,并且会导致大量重绘,降低应用程序的性能,而跟踪鼠标的速度也不如更本地化的方法快。使用这种方法有太多的负面影响。 - Sammy Guergachi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接