Java устанавливает фон из JAR и делает его прозрачным
Будьте терпеливы, я все еще новичок, без грубых комментариев, пожалуйста.
Итак, цель этого вопроса заключается в том, чтобы я научился устанавливать размытый фон моего уже прозрачного 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 производил что-то вроде этого:
Как вы можете видеть, рамка немного размывает фон компьютера и является прозрачной.
Спасибо всем заранее.
2 ответа
Java может размыть изображение, используя код, который у вас есть - проблема в том, что Java не видит изображение "под" вашим окном, поэтому оно будет размыть пустое изображение.
Полупрозрачность окна достигается за счет встроенной операционной системы. Чтобы получить эффект размытия, я не вижу простого способа. И под этим я подразумеваю, что это будет чертовски сложно. Несколько вещей, которые вы можете попробовать:
- использование
java.awt.Robot
чтобы захватить то, что находится под окном, затем используйте размытие на этом. Подводные камни: вам нужно скрывать свое окно на несколько миллисекунд при съемке, что может быть заметно для пользователя, и вы должны делать это каждый раз, когда меняется фон, что, вероятно, потребует опроса. - Используйте нативный код или хотя бы некоторые вызовы нативных библиотек через JNA. Это необходимо сделать для каждой операционной системы, которую вы хотите поддерживать. Для Mac это может начать вас. Для 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");
}
}
}
}
Если у вас есть Windows-совместимая машина с Aero, вы получите размытый фон:
Если у вас нет возможности Aero, он просто станет прозрачным без размытия.
Альфа-значения фона панели определяют, какие области видны, а какие нет. Более сложный фон, нарисованный на панели, может создавать такие эффекты, как отверстия или другие узоры. Если вам нужен равномерно полупрозрачный фон вместо эффекта градиента, используйте простой цвет фона с соответствующим значением альфа.
Моя первая догадка в "SystemInfo/black.png"
нельзя ссылаться как File
потому что это встроенный / внутренний ресурс, находящийся в вашем приложении Jar.
Для того, чтобы прочитать это (через ImageIO
) вам нужно будет использовать что-то более похожее на...
ImageIO.read(getClass().getResource("SystemInfo/black.png"))
Вместо.
Во-вторых, размытие изображения, вероятно, не приведет к тому эффекту, который вы ищете, так как это не повлияет на то, как на самом деле отображается содержимое вашего окна.
Вместо этого вам нужно будет захватить часть экрана под окном и размыть ее.
Вы можете достичь этого с помощью Robot
, но нужно будет сделать окно невидимым, когда вы делаете снимок экрана.
Это также не будет "живым" обновлением.