【发布时间】:2017-02-25 07:15:41
【问题描述】:
我使用了基于答案的透明点击覆盖(使用 jna 启用点击)
https://stackoverflow.com/a/28772306/1093872。
然而,实际可见的叠加层总是落后一步,即。当在组件上调用 repaint() 时,将显示应在上一次更新中显示的更新。
起初我怀疑是因为线程不同导致内存不一致问题。但我也尝试了使用SwingWorker 的sure-to-be-correct 方法,但仍然遇到同样的问题。
AWTUtilities.setWindowOpaque(w, false); 似乎以某种方式导致了问题,因为在我将其注释掉或将其设置为 true 后,问题就消失了,但不幸的是窗口也不透明(显然)。
我怀疑问题可能与双缓冲有关(仅在下一次绘制之前绘制后才交换缓冲区),但我真的不知道。我还尝试在组件上调用setDoubleBuffered(false) 和setDoubleBuffered(true),但这并没有改变任何东西。
我也意识到问题与 jna 部分无关,因为删除它后,问题仍然完全相同。
请注意,索引打印与绘图同时发生,因此我知道paintComponent 会及时调用,但可见更新仅在下一次调用时发生。
关于可能是什么原因以及如何解决此问题的任何想法?
import com.sun.awt.AWTUtilities;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinUser;
import javax.swing.*;
import java.awt.*;
public class OverlayUpdateTest {
private static MyJComponent myJComponent;
public static void main(String[] args) {
setupOverlayWindow();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
myJComponent.increaseIndex();
myJComponent.repaint();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
private static void setupOverlayWindow() {
Window w = new Window(null);
myJComponent = new MyJComponent();
w.add(myJComponent);
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 WinDef.HWND getHWnd(Component w) {
WinDef.HWND hwnd = new WinDef.HWND();
hwnd.setPointer(Native.getComponentPointer(w));
return hwnd;
}
private static class MyJComponent extends JComponent {
private int index = 0;
/**
* 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());
g.setColor(Color.RED);
g.drawString("i: " + index, 10, getFont().getSize() + 10);
System.out.println("i: " + index);
}
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
void increaseIndex() {
index++;
}
}
}
【问题讨论】:
标签: java swing overlay swingworker