9

透過的で、常に上部にあり、クリックスルーできるオーバーレイを Java で作成したいと考えています。この問題に関する同様 の投稿をいくつか見つけましたが、その回答に従った後でも、1 つの問題が発生しています。

私の問題は、ウィンドウ全体をクリックスルーにすることです。JFrame で動作させるのに問題はありませんが、コンポーネント(JLabel または ImagePanel) を追加すると、クリックスルー属性がそれらに引き継がれません。

アプリケーションの背景画像が必要なため、基本的に、テキスト/画像がカバーする領域をクリックするたびにウィンドウがどのようにフォーカスされるかを確認するコードが役に立たなくなります。

使用しているコードを示す前に、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 がクリックスルーされていないことに注意してください

4

3 に答える 3

4

ウィンドウを「クリックスルー」にすることの問題は、標準 API の範囲外のシステム レベルで処理されることです。これは、ウィンドウを「クリックスルー」させるために書かれたコードは、システムに依存することを意味します。そうは言っても、Windowsでこれを達成するプロセスはかなり簡単です。

Windows 2000 以降では、フラグWS_EX_LAYERED および 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;
}
于 2015-02-27T18:57:04.253 に答える
1

完全に「イベント トランスペアレント」(クリックスルーと呼ぶ) ウィンドウを作成しようとしましたが、そのトリックにはいくつかの固有の制限があるようです。

このウィンドウの例を確認してください:

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 );
}

ウィンドウとコンポーネントには次のものはありません:

  1. マウスリスナー
  2. マウスモーションリスナー
  3. マウス ホイール リスナー
  4. キーリスナー

containsまた、変更されたメソッドが原因でリスナーが存在する場合でも、コンポーネントはあらゆる種類のマウス イベントを無視する必要があります。

ご覧のとおり、コンポーネント上で何も描画されていない領域はイベント透過ですが、塗りつぶされた領域はそうではありません。残念ながら、その動作を変更するための回避策が見つかりませんでした。一部の「低レベル」の Java メソッドがイベントをブロックしているようです。

これは基本的な JComponent ベースの例にすぎません。イベントをブロックする可能性のある独自のイベントリスナーを持つ可能性のある、ラベルやボタンなどのより複雑な Swing コンポーネントについては触れません。

于 2012-06-27T14:52:20.430 に答える
1

なぜ既存のものを利用しないのJLayeredPaneですか? このブログ投稿では、テキスト、画像、動的に描画されるピクセルなど、さまざまなオーバーレイを JFrame に配置する方法を示しています。

于 2015-03-01T20:21:37.557 に答える