我想在Java中创建一个透明,始终位于顶部的叠加层,并且我可以点击。我发现了一些关于这个问题的similar posts,但即使按照他们的回答,我也遇到了一个问题。
我的问题是点击整个窗口。我在使用JFrame时没有任何问题,但是当我向其添加任何组件(JLabel或ImagePanel)时,点击后属性不会继续< / strong>对他们。
由于我想为我的应用程序提供一个背景图像,这基本上使我无法看到当我单击文本/图像所覆盖的区域时窗口如何聚焦的代码。
在我展示我正在使用的代码之前,我首先要参考these threads,它基本上描述了我想要的内容,除了在C#中。
我的目标是创建一个带有透明.png图像和一些顶部文本的叠加层,这些叠加层会在关键事件上发生变化。如果它使用JFrame或任何其他库无关紧要。我只需要它与Windows兼容。
我还想提一下,我有一些使用Java的经验,但是使用JFrame是一个新手。
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import com.sun.jna.platform.WindowUtils;
public class Overlay {
public static void main(String[] args) {
JFrame frame = new JFrame("Overlay Window");
frame.setUndecorated(true);
frame.setAlwaysOnTop(true);
frame.getRootPane().putClientProperty("apple.awt.draggableWindowBackground", false);
frame.setLocation(400, 400);
frame.getContentPane().setLayout(new java.awt.BorderLayout());
JLabel textLabel = new JLabel("I'm a label in the window", SwingConstants.CENTER);
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
frame.pack();
System.setProperty("sun.java2d.noddraw", "true");
WindowUtils.setWindowTransparent(frame, true);
WindowUtils.setWindowAlpha(frame, 1.0f);
//Using AWTUtilities gives the same result as WindowUtils
//AWTUtilities.setWindowOpaque(frame, false);
//AWTUtilities.setWindowOpacity(frame, 1.0f);
frame.setVisible(true);
}
}
请注意,问题是与被关注的窗口无关(虽然这是问题的结果),但关于 JLabel和ImagePanel不是点击
答案 0 :(得分:3)
有一个窗口的问题是&#34;点击&#34;它是在系统级别上处理的,超出了标准API的范围。这意味着任何代码都会编写一个窗口&#34;点击通过&#34;将取决于系统。话虽如此,在Windows上完成此操作的过程非常简单。
在Windows 2000及更高版本中,通过在窗口上设置标志WS_EX_LAYERED and WS_EX_TRANSPARENT,然后将点击该窗口。示例代码使用JNA来完成此任务:
public static void main(String[] args) {
Window w = new Window(null);
w.add(new JComponent() {
/**
* This will draw a black cross on screen.
*/
protected void paintComponent(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, getHeight() / 2 - 10, getWidth(), 20);
g.fillRect(getWidth() / 2 - 10, 0, 20, getHeight());
}
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
});
w.pack();
w.setLocationRelativeTo(null);
w.setVisible(true);
w.setAlwaysOnTop(true);
/**
* This sets the background of the window to be transparent.
*/
AWTUtilities.setWindowOpaque(w, false);
setTransparent(w);
}
private static void setTransparent(Component w) {
WinDef.HWND hwnd = getHWnd(w);
int wl = User32.INSTANCE.GetWindowLong(hwnd, WinUser.GWL_EXSTYLE);
wl = wl | WinUser.WS_EX_LAYERED | WinUser.WS_EX_TRANSPARENT;
User32.INSTANCE.SetWindowLong(hwnd, WinUser.GWL_EXSTYLE, wl);
}
/**
* Get the window handle from the OS
*/
private static HWND getHWnd(Component w) {
HWND hwnd = new HWND();
hwnd.setPointer(Native.getComponentPointer(w));
return hwnd;
}
答案 1 :(得分:1)
为什么不利用现有的JLayeredPane
? This blog post演示了在JFrame上放置各种各样的叠加层,包括文本,图像和动态绘制的像素。
答案 2 :(得分:0)
我试图完全“事件透明”(在你调用它时点击)窗口,但似乎有一些本机限制。
选中此窗口示例:
public static void main ( String[] args )
{
Window w = new Window ( null );
w.add ( new JComponent ()
{
protected void paintComponent ( Graphics g )
{
g.setColor ( Color.BLACK );
g.fillRect ( 0, getHeight () / 2 - 10, getWidth (), 20 );
g.fillRect ( getWidth () / 2 - 10, 0, 20, getHeight () );
}
public Dimension getPreferredSize ()
{
return new Dimension ( 100, 100 );
}
public boolean contains ( int x, int y )
{
return false;
}
} );
AWTUtilities.setWindowOpaque ( w, false );
AWTUtilities.setWindowOpacity ( w, 0.5f );
w.pack ();
w.setLocationRelativeTo ( null );
w.setVisible ( true );
}
窗口和组件没有任何:
如果由于修改后的contains
方法有任何侦听器,组件也应该忽略任何类型的鼠标事件。
如您所见 - 组件上未绘制任何内容的区域是事件透明的,但填充区域不是。不幸的是,我没有找到任何改变这种行为的解决方法。似乎某些“低级”java方法阻止了这些事件。
这只是一个基于JComponent的基本示例。我甚至没有说过更复杂的Swing组件,比如标签,按钮e.t.c.可能有自己的事件监听器,可以阻止事件。