2017-02-24 3 views
0

回答に基づいて透明なクリックスルーオーバーレイを使用しました(jnaを使用してクリックスルーを有効にします) https://stackoverflow.com/a/28772306/1093872。 しかし、実際の表示可能なオーバーレイは常に1つのステップの後ろにあります。コンポーネント上でrepaint()が呼び出されると、前の更新で示されたはずの更新が表示されます。透明スイングオーバーレイを正しく更新するにはどうすればよいですか?

最初は、スレッドが異なるためにメモリの不整合の問題が疑われました。しかし、私はSwingWorkerを使ってsure-to-be-correctのアプローチを試しても、同じ問題に直面しました。

The overlay only updated after the next call to repaint, although I used a generous 2000ms delay

AWTUtilities.setWindowOpaque(w, false);私はそれをコメントアウトまたはtrueに設定した後、問題が消えるので、何らかの方法で問題を引き起こしているようだが、残念ながら窓は、(明らかに)透明ではありません。

The update is correct after disabling the transparency

私はこの問題は、(バッファが次の塗料前にのみ塗装した後に交換されていません)ダブルバッファリングに関連したものになるかもしれない疑いが、私は本当に知りません。私はまた、コンポーネントの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++; 
     } 
    } 
} 

答えて

0

...


は、問題を解決しました。理由は分かりませんが、私はそれに満足しています。

関連する問題