Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing Cursor in Java with some Transparency

I have a 35x40 px. png image I want to use as a custom cursor in a Swing application. The image has a glow so contains alpha transparency values. Problem is when I attempt to use the conventional method of using the Toolkit to generate the custom cursor I get black pixels where alpha transparency values should be.

Here is the image I am using for a cursor: https://dl.dropbox.com/u/1186703/cursor.png

Here is my code:

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

Here is the current result:

result

Edit it seems that this method does not work well cross platform, for instance Windows LAF doesn't support semi-transparency. I am therefore looking for any solution to get this to work on windows, assuming this implementation does work on Mac OSX, i can just specify in code which implementation to use based on which operating system the app is running on.

like image 296
Sammy Guergachi Avatar asked Nov 10 '12 21:11

Sammy Guergachi


4 Answers

Your code and cursor image actually produces the desired result on MacOS X 10.7.5 (jdk 1.6.0_31) with semi-transparent blue border. But I did notice an off comment in this answer saying that partial transparency is not supported in the default Windows look and feel.

like image 136
Charlie Avatar answered Nov 20 '22 14:11

Charlie


The problem your having is to do with the Cursor class which (under Windows) doesn't take into account the transparency values of the image

This is, by no means, a "real" solution, but is more about "fudging" the result...

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

I got the idea for here

like image 44
MadProgrammer Avatar answered Nov 20 '22 13:11

MadProgrammer


If you are desperate and absolutely must have transparent cursor, no matter the consequences, you can use JNI and set the cursor manually using Win32 API. Windows since XP support alpha cursors, so you should be ok with that.

But you lose platform independence. And based on Windows settings, the alpha blending might be turned off for that particular user.

like image 41
Jakub Zaverka Avatar answered Nov 20 '22 14:11

Jakub Zaverka


An alternative is to fake a cursor.

Take a look at Alexander Potochkin's Well Behaved GlassPane.

In particular, run the sample code, choose Options>GlassPane is Visible and Options>Final GlassPane.

Starting from this, load up a cursor image that is completely transparent, then paint a proper, alpha-blended cursor on the glasspane.

like image 2
Devon_C_Miller Avatar answered Nov 20 '22 14:11

Devon_C_Miller