Java透明窗口

10

我正在尝试创建一个圆形窗口,该窗口跟随鼠标移动并将点击事件传递到底层窗口。

我之前用Python和Qt来实现(参见Python overlay window),但是后来我改用Java和Swing。然而,我无法使窗口透明。我尝试了此方法,但它并不起作用,但我认为我的系统支持透明度,因为如果我启动Screencast-O-Matic(这是一个使用Java编写的程序),矩形实际上是透明的。

我应该如何实现类似的效果?(我在Linux KDE4上)


1
你有解决这个问题的方法吗?我也遇到了同样的问题。我开发了一个类似Screencast-O-Matic的应用程序,它可以在Windows操作系统上很好地运行,但在Linux上无法正常工作。如果你找到了任何解决方案,请在这里提出建议:http://stackoverflow.com/questions/25009276/swing-works-different-on-different-platform - tarkikshah
1
不,我因为在Java上遇到了其他问题,所以又转回PyQt来制作我的屏幕录制应用程序。 - Lord Spectre
5个回答

11
为什么Java教程 如何创建半透明和形状窗口 没有起作用?你正在使用最新的Java 6或Java 7吗?
Java Magazine的5月/6月期刊中,有一篇关于需要Java 7的形状和透明窗口的教程。您可能需要注册Java Magazine才能阅读它。请尝试在您的系统上运行它。
import java.awt.*; //Graphics2D, LinearGradientPaint, Point, Window, Window.Type;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

/**
 * From JavaMagazine May/June 2012
 * @author josh
 */
public class ShapedAboutWindowDemo {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //switch to the right thread
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("About box");
                //turn of window decorations
                frame.setUndecorated(true);
                //turn off the background
                frame.setBackground(new Color(0,0,0,0));
                frame.setContentPane(new AboutComponent());
                frame.pack();
                //size the window
                frame.setSize(500, 200);
                frame.setVisible(true);
                //center on screen
                frame.setLocationRelativeTo(null);
            }
        }
        );
    }

    private static class AboutComponent extends JComponent {
        public void paintComponent(Graphics graphics) {
            Graphics2D g = (Graphics2D) graphics;

            //create a translucent gradient
            Color[] colors = new Color[]{
                           new Color(0,0,0,0)
                            ,new Color(0.3f,0.3f,0.3f,1f)
                            ,new Color(0.3f,0.3f,0.3f,1f)
                            ,new Color(0,0,0,0)};
            float[] stops = new float[]{0,0.2f,0.8f,1f};
            LinearGradientPaint paint = new LinearGradientPaint(
                                        new Point(0,0), new Point(500,0),
                                        stops,colors);
            //fill a rect then paint with text
            g.setPaint(paint);
            g.fillRect(0, 0, 500, 200);
            g.setPaint(Color.WHITE);
            g.drawString("My Killer App", 200, 100);
        }
    }
}

我使用的是Java 6,因此我在页面底部使用了兼容性方法...通过你的例子,我得到了这个链接 - Lord Spectre
好的。你所引用的Java教程需要Java 6更新10,只要你有这个版本,它应该可以工作。如果没有,那么可能存在Linux兼容性问题,在这种情况下,我建议你升级到JDK 7并查看是否解决了问题。 - Thorn

4

如果您使用Java 6,需要使用私有API AWTUtilities。请查看Java SE 6 Update 10 API获取更多详细信息。

示例

这是一种快速的技巧,但它可以传达思想。

public class TransparentWindow {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                MyFrame frame = new MyFrame();
                frame.setUndecorated(true);

                String version = System.getProperty("java.version");
                if (version.startsWith("1.7")) {


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

                    System.out.println("Transparent from under Java 7");
                    /* This won't run under Java 6, uncomment if you are using Java 7
                    System.out.println("isPerPixelAlphaTranslucent = " + graphicsDevice.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT));
                    System.out.println("isPerPixelAlphaTransparent = " + graphicsDevice.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT));
                    System.out.println("isPerPixelAlphaTranslucent = " + graphicsDevice.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.TRANSLUCENT));
                    */
                    frame.setBackground(new Color(0, 0, 0, 0));

                } else if (version.startsWith("1.6")) {

                    System.out.println("Transparent from under Java 6");
                    System.out.println("isPerPixelAlphaSupported = " + supportsPerAlphaPixel());
                    setOpaque(frame, false);

                }

                frame.setSize(400, 400);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

            }
        });

    }

    public static class MyFrame extends JFrame {

        public MyFrame() throws HeadlessException {

            setContentPane(new MyContentPane());
            setDefaultCloseOperation(EXIT_ON_CLOSE);

            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {

                    if (e.getClickCount() == 2) {

                        dispose();

                    }

                }
            });

        }
    }

    public static class MyContentPane extends JPanel {

        public MyContentPane() {

            setLayout(new GridBagLayout());
            add(new JLabel("Hello, I'm a transparent frame under Java " + System.getProperty("java.version")));

            setOpaque(false);

        }

        @Override
        protected void paintComponent(Graphics g) {

            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.BLUE);

            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
            g2d.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);

        }
    }

    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);
//                com.sun.awt.AWTUtilities.setWindowOpaque(this, opaque);
//                ((JComponent) window.getContentPane()).setOpaque(opaque);

            }

        } catch (Exception exp) {
        }

    }

    public static void setOpacity(Window window, float opacity) {

        try {

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

                Method method = awtUtilsClass.getMethod("setWindowOpacity", Window.class, float.class);
                method.invoke(null, window, opacity);

            }

        } catch (Exception exp) {

            exp.printStackTrace();

        }

    }

    public static float getOpacity(Window window) {

        float opacity = 1f;
        try {

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

                Method method = awtUtilsClass.getMethod("getWindowOpacity", Window.class);
                Object value = method.invoke(null, window);
                if (value != null && value instanceof Float) {

                    opacity = ((Float) value).floatValue();

                }

            }

        } catch (Exception exp) {

            exp.printStackTrace();

        }


        return opacity;

    }
}

在Windows 7上,它会生成以下结果:
在Java 6下: Java6 在Java 7下: Java7

我试了,但另一个甚至都没编译通过。 - Lord Spectre
我不确定你的意思,可以看看我的例子。 - MadProgrammer
我正在使用Java 6,它只能编译AWTUtilities,但是当我运行它时却没有透明度。 - Lord Spectre
看起来你正在运行 Java 版本 10 之前的版本或者它不被支持。请查看 http://java.sun.com/developer/technicalArticles/GUI/translucent_shaped_windows/#Determining-the-Support-for-a-Desired-Effect,其中包含示例代码以确定可用的内容。 - MadProgrammer

3

我猜这会有效,我已经试过了。如果要使JFrame或窗口透明,您需要首先取消装饰Undecorated(true)。以下是示例代码:

import javax.swing.*;
import com.sun.awt.AWTUtilities;
import java.awt.Color;   

    class transFrame {
      private JFrame f=new JFrame();
      private JLabel msg=new JLabel("Hello I'm a Transparent Window");

     transFrame() {
       f.setBounds(400,150,500,500);
       f.setLayout(null);
       f.setUndecorated(true);     // Undecorates the Window
       f.setBackground(new Color(0,0,0,25));  // fourth index decides the opacity
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       msg.setBounds(150,250,300,25);
       f.add(msg);
       f.setVisible(true);
      }

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

     }

唯一的问题是,您需要添加自己的代码来使用按钮关闭和最小化窗口。

2
如果您想自己完成此操作而不使用外部库,可以启动一个线程执行以下操作:
  • 将透明窗口设置为不可见
  • 对桌面进行截屏
  • 将此截屏作为窗口的背景图像
或者您可以使用JavaFX

我无法这样做,因为窗口会跟随鼠标移动,所以我必须定时截屏,而且我认为这是一种低效的方法。 - Lord Spectre
那么使用另一个选项呢? - Quick n Dirty
抱歉,我找不到适用于Linux和JDK 6的JavaFX。 - Lord Spectre
JavaFX for Linux目前以预览形式提供。JavaFX SDK预览版的系统要求在Linux 发布说明中指出需要JDK 6u26+。 - jewelsea

0

我也遇到了同样的问题。经过数小时的搜索,我终于找到了问题所在!如果你想要创建一个透明的JFrame,这些是你必须编写的代码:

public void enableTransparentWindow(float opacity) {
        GraphicsEnvironment ge =
                GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();

        f.setLocationRelativeTo(null);
        f.setBackground(new Color(0, 0, 0));
        //If translucent windows aren't supported, exit.
        f.setUndecorated(true);

        if (!gd.isWindowTranslucencySupported(TRANSLUCENT)) {
            System.err.println(
                    "Translucency is not supported");
            System.exit(0);
        }
        f.setOpacity(opacity);
    }

不要忘记在此代码后调用setVisible()方法。
编程愉快!

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