【问题标题】:Java setting background from JAR and making it transparentJava 从 JAR 设置背景并使其透明
【发布时间】:2014-02-25 22:03:58
【问题描述】:

请耐心等待,我还是个初学者,请不要粗鲁。

所以这个问题的目标是让我学习如何将我已经透明的 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)

如果需要,setOpacity();功能:

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

我的主要目标是让 JFrame 产生这样的东西:

如您所见,边框稍微模糊了电脑背景,并且是透明的。

提前谢谢大家。

【问题讨论】:

标签: java swing


【解决方案1】:

Java 可以使用您拥有的代码模糊图像 - 问题是 Java 看不到窗口“下方”的图像,因此它会模糊空白图像。

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

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

但最终,鉴于这些技术非常先进,并且您说您是初学者(尽管您使用 Image 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 机器,你会得到一个模糊的背景:

如果您没有 Aero 功能,它将退回到只是半透明而没有模糊。

面板背景的 alpha 值控制哪些区域是透明的,哪些不是。在面板上绘制的更复杂的背景可以产生像孔或其他图案这样的效果。如果您需要均匀半透明的背景而不是渐变效果,请改用具有适当 alpha 值的简单背景颜色。

【讨论】:

  • 像这样使用 JNI(这是一个很酷的想法)会阻止您将任何基于 Java 的组件添加到窗口...
  • @MadProgrammer JNI 代码绝对有可能与 Java Frames 和 JFrames 进行交互。 JNA 的示例,JNI 的示例。
  • @MadProgrammer 您将开始在 Java 中创建一个 JFrame,使其可显示,获取 hWnd 并在本机代码中对其进行调整,然后在 Java 中像平常一样对待它,添加/删除组件等。
【解决方案2】:

我对@9​​87654321@ 的第一个猜测不能被引用为File,因为它是一个嵌入/内部资源,驻留在您的应用程序 Jar 中。

为了阅读它(通过ImageIO),您需要使用类似...

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

相反。

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

相反,您需要捕获窗口下方的屏幕部分并对其进行模糊处理。

您可以使用Robot 实现此目的,但需要在您抓取屏幕截图时使窗口不可见。

它也不会是“实时”更新。

【讨论】:

  • 看起来有点复杂,你认为我最好在 Photoshop 中创建一个模糊的背景吗?
  • 您模糊的任何“静态”图像都不会影响图像后面的桌面的呈现方式...
猜你喜欢
  • 2018-12-25
  • 2016-10-09
  • 1970-01-01
  • 2021-04-27
  • 1970-01-01
  • 2012-07-27
  • 1970-01-01
  • 1970-01-01
  • 2011-04-14
相关资源
最近更新 更多