Java: Making a window click-through (including text/images)

后端 未结 3 550
隐瞒了意图╮
隐瞒了意图╮ 2020-12-05 08:52

I want to create an overlay in Java that is transparent, always on top, and that I can click-through. I\'ve found some sim

相关标签:
3条回答
  • 2020-12-05 09:15

    Why not just make use of the existing JLayeredPane? This blog post demonstrates putting a wide variety of overlays on a JFrame, including text, images, and dynamically drawn pixels.

    0 讨论(0)
  • 2020-12-05 09:20

    I tried to make fully "event-transparent" (click-through as you call it) window, but there seems to be some native restrictions on that trick.

    Check this window example:

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

    Window and component does NOT have any:

    1. Mouse listeners
    2. Mouse motion listeners
    3. Mouse wheel listeners
    4. Key listeners

    Also the component should ignore any kind of mouse events EVEN if there are any listeners due to the modified contains method.

    As you can see - the area where nothing is painted on the component is event-transparent, but the filled area is not. Unluckly i didn't find any workaround to change that behavior. Seems that some "low-level" java methods are blocking the events.

    And this is just a basic JComponent-based example. I don't even say about more complex Swing components like labels, buttons e.t.c. which might have their own event-listeners which could block events.

    0 讨论(0)
  • 2020-12-05 09:34

    The problem with having a window be "click through" is that it's handled on a system level, outside the scope of the standard APIs. This means that any code written to make a window "click through" will be system dependant. That being said, the process for accomplishing this on windows is rather straight forward.

    On Windows 2000 and later, by setting the flags WS_EX_LAYERED and WS_EX_TRANSPARENT on a window, the window will then be click through. Example code uses JNA to accomplish this:

    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;
    }
    
    0 讨论(0)
提交回复
热议问题