回答に基づいて透明なクリックスルーオーバーレイを使用しました(jnaを使用してクリックスルーを有効にします) https://stackoverflow.com/a/28772306/1093872。 しかし、実際の表示可能なオーバーレイは常に1つのステップの後ろにあります。コンポーネント上でrepaint()
が呼び出されると、前の更新で示されたはずの更新が表示されます。透明スイングオーバーレイを正しく更新するにはどうすればよいですか?
最初は、スレッドが異なるためにメモリの不整合の問題が疑われました。しかし、私はSwingWorker
を使ってsure-to-be-correctのアプローチを試しても、同じ問題に直面しました。
AWTUtilities.setWindowOpaque(w, false);
私はそれをコメントアウトまたはtrueに設定した後、問題が消えるので、何らかの方法で問題を引き起こしているようだが、残念ながら窓は、(明らかに)透明ではありません。
私はこの問題は、(バッファが次の塗料前にのみ塗装した後に交換されていません)ダブルバッファリングに関連したものになるかもしれない疑いが、私は本当に知りません。私はまた、コンポーネントのsetDoubleBuffered(false)
とsetDoubleBuffered(true)
を呼び出してみましたが、何も変わりません。
また、この問題はjnaパートに関連していないことがわかりました。これを削除しても、問題はまったく同じです。
インデックス印刷は図面と同時に行われるので、paintComponent
は時間内に呼び出されることがわかっていますが、表示される更新は次の呼び出しでのみ発生します。
何が原因である可能性があり、これを修正する方法はありますか? Window w = new JWindow();
からWindow w = new Window(null);
を変更する多くの試行錯誤私が働いて解決策を見つけた後
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++;
}
}
}