有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

swing Java从JAR设置背景并使其透明

耐心点,我还是个初学者,请不要发表粗鲁的评论

所以这个问题的目的是让我学会如何将我已经透明的JFrame的背景设置为模糊。这就是我现在拥有的

Current JFrame

所以你可以看到它是透明的,但不是模糊的。我在想,也许Java有一些过程,可以模糊JAR中的图像,并将其用作背景,而不改变原始图像。所以我看了又看,但我发现什么都帮不了我

如上图所示,JFrame的背景是一个没有文本的标签,而是“背景图像”作为标签的图标

JAR的组织:

META-INF(folder) > MANIFEST.MF

SystemInfo(folder) > classes and background image

这是我到目前为止的代码,但它不起作用

        setOpacity(); // sets opacity of the background
        Color c = Color.WHITE; // default color
            setColor(c);

        //background = (new JLabel((Icon) new ImageIcon(a)));
        BufferedImage mshi = null;    
        try{mshi = ImageIO.read(new File("SystemInfo/black.png"));}catch(Exception e){e.printStackTrace();}

        BufferedImage databuf = new BufferedImage(mshi.getWidth(null),
                mshi.getHeight(null),
                BufferedImage.TYPE_INT_BGR);

        Graphics g = databuf.getGraphics();
        g.drawImage(mshi, 455, 255, null);

        float[] blurKernel = {
            1 / 9f, 1 / 9f, 1 / 9f,
            1 / 9f, 1 / 9f, 1 / 9f,
            1 / 9f, 1 / 9f, 1 / 9f
        };

        BufferedImageOp blur = new ConvolveOp(new Kernel(3, 3, blurKernel));
        mshi = blur.filter(mshi, new BufferedImage(mshi.getWidth(),
                mshi.getHeight(), mshi.getType()));
        g.dispose();
        //background = (new JLabel((Icon) new ImageIcon(mshi)));
        background.setIcon((Icon)new JLabel(new ImageIcon(mshi)));

上述代码产生的错误:

javax.imageio.IIOException: Can't read input file!
    at javax.imageio.ImageIO.read(ImageIO.java:1301)
    at SystemInfo.GuiMain.cinitComponents(GuiMain.java:150)
    at SystemInfo.GuiMain.<init>(GuiMain.java:30)
    at SystemInfo.GuiMain$8.run(GuiMain.java:256)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at SystemInfo.GuiMain.cinitComponents(GuiMain.java:152)
    at SystemInfo.GuiMain.<init>(GuiMain.java:30)
    at SystemInfo.GuiMain$8.run(GuiMain.java:256)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

如果需要,设置不透明度();功能:

        float fOpacity = (float)opacity/10;
        String sOpacity = Float.toString(fOpacity)+"f";
        this.setOpacity(Float.parseFloat(sOpacity));

我的主要目标是让JFrame生成如下内容:

What I would like to see

正如你所看到的,这个框架稍微模糊了计算机背景,是透明的

提前谢谢大家


共 (2) 个答案

  1. # 1 楼答案

    我对"SystemInfo/black.png"的第一个猜测不能被引用为File,因为它是一个嵌入式/内部资源,驻留在应用程序Jar中

    为了阅读它(通过ImageIO),你需要使用更像

    ImageIO.read(getClass().getResource("SystemInfo/black.png"))
    

    相反

    其次,模糊图像可能不会产生您想要的效果,因为它不会对窗口后面的内容的实际绘制方式产生任何影响

    相反,你需要捕捉窗口下方的屏幕部分,并将其模糊

    您可以通过使用Robot来实现这一点,但需要在抓取屏幕截图时使窗口不可见

    它也不会是“实时”更新

  2. # 2 楼答案

    Java可以使用您拥有的代码模糊图像——问题是Java看不到窗口下方的图像,所以它会模糊空白图像

    窗口半透明性是通过本机操作系统实现的。要获得模糊效果,我看不出一个简单的方法。我的意思是这将非常困难。你可以尝试以下几件事:

    • 使用java.awt.Robot捕捉窗口下方的内容,然后对其使用模糊。陷阱:在进行用户可能会注意到的捕获时,需要将窗口隐藏几毫秒,并且每次背景发生变化时都需要这样做,这可能会涉及轮询
    • 使用本机代码或至少通过JNA调用本机库。您需要为每个想要支持的操作系统执行此操作。对于Mac,this可能会让你开始。对于Windows,也许可以开始查看DWM API,也许可以使用DwmEnableBlurBehindWindow功能

    但归根结底,考虑到这些技术非常先进,而且您说自己是初学者(尽管您使用图像I/O OK进行了模糊处理),您可能只想解决半透明窗口的问题


    (编辑:添加Windows示例)

    对于Windows,您可以使用JNA调用DwmEnableBlurBehindWindow,而且效果很好。您必须使用Java 7或更高版本才能使用

    例如:

    package dwmtest;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.GradientPaint;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Paint;
    import java.util.Arrays;
    import java.util.List;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    import com.sun.jna.Native;
    import com.sun.jna.Structure;
    import com.sun.jna.platform.win32.WinDef.HWND;
    import com.sun.jna.ptr.IntByReference;
    import com.sun.jna.win32.StdCallLibrary;
    import com.sun.jna.win32.W32APIOptions;
    
    public class DwmWindow extends JFrame
    {
        public static void main(String... args)
        throws Exception
        {
            JFrame.setDefaultLookAndFeelDecorated(true);
    
            DwmWindow f = new DwmWindow();
            f.setSize(600, 500);
            f.setBackground(new Color(0,0,0,0));
            f.setTitle("Hello");
            TranslucentPanel panel = new TranslucentPanel();
            panel.setLayout(new BorderLayout());
            JLabel label = new JLabel("My background is blurry!");
            label.setFont(new Font("Dialog", Font.BOLD, 48));
            panel.add(label, BorderLayout.CENTER);
            f.add(panel);
            f.setDefaultCloseOperation(EXIT_ON_CLOSE);
            f.setVisible(true);
    
            HWND hwnd = new HWND(Native.getWindowPointer(f));
            Dwmapi.DWM_BLURBEHIND pBlurBehind = new Dwmapi.DWM_BLURBEHIND();
            pBlurBehind.dwFlags = Dwmapi.DWM_BB_ENABLE;
            pBlurBehind.fEnable = true;
            pBlurBehind.fTransitionOnMaximized = false;
            Dwmapi.INSTANCE.DwmEnableBlurBehindWindow(hwnd, pBlurBehind);
        }
    
        private static class TranslucentPanel extends JPanel
        {
            @Override
            protected void paintComponent(Graphics g) 
            {
                if (g instanceof Graphics2D) {
                    final int R = 240;
                    final int G = 240;
                    final int B = 240;
    
                    Paint p = new GradientPaint(0.0f, 0.0f, new Color(R, G, B, 0), 0.0f, getHeight(), new Color(R, G, B, 255), true);
                    Graphics2D g2d = (Graphics2D)g;
                    g2d.setPaint(p);
                    g2d.fillRect(0, 0, getWidth(), getHeight());
                }
            }
        }
    
        public static interface Dwmapi extends StdCallLibrary
        {
            Dwmapi INSTANCE = (Dwmapi)Native.loadLibrary("Dwmapi", Dwmapi.class, W32APIOptions.UNICODE_OPTIONS);
    
            int DWM_BB_ENABLE = 0x00000001;
    
            boolean DwmEnableBlurBehindWindow(HWND hWnd, DWM_BLURBEHIND pBlurBehind);
    
            public static class DWM_BLURBEHIND extends Structure 
            {
                public int dwFlags;
                public boolean fEnable;
                public IntByReference hRgnBlur;
                public boolean fTransitionOnMaximized;
    
                @Override
                protected List getFieldOrder() 
                {
                    return Arrays.asList("dwFlags", "fEnable", "hRgnBlur", "fTransitionOnMaximized");
                }
            }
        }
    }
    

    如果你有一台支持Aero的Windows机器,你会得到一个模糊的背景:

    Blurry Java window

    如果你没有航空能力,它会退回到半透明而没有模糊

    面板背景的alpha值控制哪些区域是透明的,哪些区域不是。在面板上画一个更复杂的背景可以产生像洞或其他图案这样的效果。如果你需要一个均匀的半透明背景,而不是渐变效果,可以使用一个简单的背景色,并使用合适的alpha值