How to remove drop shadow of Java AWT Frame on OSX

2019-06-05 18:14发布

问题:

Is it possible to disable the drop shadow of a Java AWT application on OS X? I want to create a transparent window, which works fine, but I cannot get rid of the drop shadow.

If I was using a JFrame this could be done using:

 JRootPane root = frame.getRootPane();
 root.putClientProperty( "Window.shadow", Boolean.FALSE );

Any similar possibility for an AWT Frame?

I' using the Framework Processing and my code there looks like this:

void setup(){
  frame.removeNotify();
  frame.setUndecorated(true);
}

Processing itself does the main Frame creation, here is the source.

回答1:

This is a simple application that uses a transparent window running on Max OS X 10.7.5 under Java 7 (has run under Java 6) which has no problems...

Share some code so we can replicate the issue

Updated from feedback

I have tested this on Mac OS 10.7.5 & 10.8.2, using JDK 1.7.0_07 & 1.6.0_37

Without and with Window.shadow property...

Without going into a lot of tests and without further information, I would suggest you want to make this call as early as you can. If that doesn't work, make it the last call before you make the window visible.

This may be related to how Java/AWT connects to it's native peer, presumably, once the connection is made, you will no longer be able to effect these kinds of properties...

public class TransparentFrame {

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

    public TransparentFrame() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }
                // Use this to test the transparentancy API
                //doTransparentFrame();
                doDropShadow();
            }

        });
    }

    protected void doDropShadow() {
        String version = System.getProperty("java.version");
        System.out.println(version);
        JFrame frame = new JFrame("Testing");
        JRootPane root = frame.getRootPane();
        root.putClientProperty("Window.shadow", root);
        frame.setUndecorated(true);
        frame.setContentPane(new ContentPane());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(new ImagePane());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    protected void doTransparentFrame() {
        JFrame frame = new JFrame("Testing");
        frame.setUndecorated(true);
        frame.setContentPane(new ContentPane());

        String version = System.getProperty("java.version");
        System.out.println(version);
        if (version.startsWith("1.7")) {
            frame.setBackground(new Color(0, 0, 0, 0));
        } else if (version.startsWith("1.6")) {
            if (supportsPerAlphaPixel()) {
                setOpaque(frame, false);
            } else {
                System.out.println("Per Pixel Alphering is not support with Java " + version);
                System.exit(1);
            }
        } else {
            System.out.println("Per Pixel Alphering is not support with Java " + version);
            System.exit(1);
        }
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
        frame.add(new ImagePane());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static boolean supportsPerAlphaPixel() {

        boolean support = false;

        try {

            Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
            support = true;

        } catch (Exception exp) {
        }

        return support;

    }

    public static void setOpaque(Window window, boolean opaque) {

        try {

            Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
            if (awtUtilsClass != null) {

                Method method = awtUtilsClass.getMethod("setWindowOpaque", Window.class, boolean.class);
                method.invoke(null, window, opaque);

            }

        } catch (Exception exp) {
        }

    }

    public class ContentPane extends JPanel {

        public ContentPane() {
            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.RED);
            g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
        }

    }

    public class ImagePane extends JPanel {

        private BufferedImage background;
        private BufferedImage offImage;
        private Ellipse2D offButton;
        private boolean mouseIn;

        public ImagePane() {
            setOpaque(false);
            try {
                background = ImageIO.read(new File("tamagotchi400.png"));
                offImage = ImageIO.read(new File("powerSmall.png"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            offButton = new Ellipse2D.Float(212, 330, 25, 25);
            MouseAdapter handler = new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1) {
                        if (offButton.contains(e.getPoint())) {
                            Window window = SwingUtilities.getWindowAncestor(ImagePane.this);
                            if (window != null) {
                                window.dispose();
                            }
                        }
                    }
                }

                @Override
                public void mouseMoved(MouseEvent e) {
                    Cursor cursor = Cursor.getDefaultCursor();
                    if (offButton.contains(e.getPoint())) {
                        cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
                    }
                    setCursor(cursor);
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    mouseIn = true;
                    repaint();
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    mouseIn = false;
                    repaint();
                }

            };
            addMouseListener(handler);
            addMouseMotionListener(handler);
        }

        @Override
        public Dimension getPreferredSize() {
            return background == null ? new Dimension(400, 400) : new Dimension(background.getWidth(), background.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (background != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                int x = (getWidth() - background.getWidth()) / 2;
                int y = (getHeight() - background.getHeight()) / 2;
                g2d.drawImage(background, x, y, this);
                if (mouseIn && offImage != null) {
                    g2d.drawImage(offImage, (int) offButton.getX(), (int) offButton.getY(), this);
                }
                g2d.dispose();
            }
        }

    }

}

The code also includes transparency test code to test the transparency API now available in Java 1.7 and Java 1.6_10+. I've used this code successfully in a number of projects, its less cumbersome then the AWT Robot "hack" and provides a live back ground, but that's a choice you need to make.

Updated

Demonstration using java.awt.Frame

public class TestTransparentFrame {

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

    public TestTransparentFrame() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception exp) {
                }

                Frame frame = new Frame("Test");
                frame.setUndecorated(true);
                setOpaque(frame, false);
                frame.addWindowListener(new WindowAdapter() {
                    @Override
                    public void windowClosing(WindowEvent e) {
                        System.exit(0);
                    }

                });
                frame.setLayout(new BorderLayout());
                frame.add(new ContentPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class ContentPane extends JPanel {

        private BufferedImage background;

        public ContentPane() {
            try {
                background = ImageIO.read(new File("duke.png"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            setOpaque(false);
            JButton close = new JButton("Close");
            close.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    SwingUtilities.getWindowAncestor(ContentPane.this).dispose();
                }
            });
            setBorder(new LineBorder(Color.RED));
            setLayout(new GridBagLayout());
            add(close);
        }

        @Override
        public Dimension getPreferredSize() {
            return background == null ? new Dimension(200, 200) : new Dimension(background.getWidth(), background.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (background != null) {
                g.drawImage(background, 0, 0, this);
            }
        }

    }

    public static boolean supportsPerAlphaPixel() {

        boolean support = false;
        String version = System.getProperty("java.version");
        if (version.startsWith("1.6")) {
            try {
                Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
                support = true;
            } catch (Exception exp) {
            }
        } else if (version.startsWith("1.7")) {
            try {
                Class<?> winTransClass = Class.forName("java.awt.GraphicsDevice$WindowTranslucency");
                Field field = winTransClass.getField("TRANSLUCENT");

                GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
                GraphicsDevice gd = ge.getDefaultScreenDevice();

                gd.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.TRANSLUCENT);

                Method isWindowTranslucencySupported = GraphicsDevice.class.getMethod("isWindowTranslucencySupported", winTransClass);
                System.out.println(isWindowTranslucencySupported);

                Object value = isWindowTranslucencySupported.invoke(gd, field.get(null));
                if (value instanceof Boolean) {
                    support = ((Boolean) value).booleanValue();
                }

            } catch (Exception exp) {
            }
        }
        return support;
    }

    public static void setOpaque(Window window, boolean opaque) {

        String version = System.getProperty("java.version");
        if (version.startsWith("1.6")) {
            try {
                Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
                if (awtUtilsClass != null) {
                    Method method = awtUtilsClass.getMethod("setWindowOpaque", Window.class, boolean.class);
                    method.invoke(null, window, opaque);
                }
            } catch (Exception exp) {
            }
        } else if (version.startsWith("1.7")) {
            Color color = UIManager.getColor("Panel.background");
            if (opaque) {
                color = new Color(color.getRed(), color.getGreen(), color.getBlue());
            } else {
                color = new Color(color.getRed(), color.getGreen(), color.getBlue(), 0);
            }
            window.setBackground(color);
        }

    }

}

Tested on Windows 7 Java 1.6 & 1.7, Mac OS 10.7.5 & 10.8.2, using JDK 1.7.0_07 & 1.6.0_37

It appears that you don't understand the window hierarchy in Java

All "windows" in Java derive from java.awt.Window.

JFrame extends Frame which extends Window.



回答2:

Using this line, it works:

AWTUtilities.setWindowOpaque(frame, false);

Eclipse prints out a warning on this and I had to change some settings to comile it, so I guess there may be better ways. I read here, that this is supported since OS X 10.6 (Lion).