8

I'm making a pseudo transparent window in pygame with the intent of displaying varied info like a "HUD"

The script uses PIL to grab an image of the desktop and use it as the background of the window.

A simple version:

import pygame as py
from ctypes import windll
import ImageGrab, Image

SetWindowPos = windll.user32.SetWindowPos

py.init()

def get_image():
    im = ImageGrab.grab((0,0,window_x,window_y))
    mode = im.mode
    size = im.size
    data = im.tobytes()
    im = py.image.fromstring(data,size,mode)
    return im

window_x = 1920
window_y = 100

background = py.Surface((window_x,window_y))
background.blit(get_image(),(0,0))

window_pos = (0,0)


screen = py.display.set_mode((window_x,window_y),py.HWSURFACE|py.NOFRAME)

SetWindowPos(py.display.get_wm_info()['window'],-1,0,0,0,0,0x0001)

clock = py.time.Clock()

done = False

while not done:
    for event in py.event.get():
        if event.type == py.QUIT:
            done = True
    screen.blit(background,(0,0))
    py.display.flip()
    clock.tick(30)

py.quit()

This creates a Pygame window at the top of the screen.

My problem is that the Pygame window blocks any mouse interaction with anything beneath it.

Is there a way to allow mouse events to be ignored and go 'through' the window, like for example clicking on a desktop icon, underneath a Pygame window.

DCA-
  • 1,262
  • 2
  • 18
  • 33
  • What is your target operating system for that? There are different methods for doing it on Mac OS X, Windows, Linux. If you can mention that I can try to link a specific piece of code. – Nandeep Mali May 19 '16 at 10:22
  • I'm currently using and prioritise Windows, but a Linux solution would also be helpful. – DCA- May 19 '16 at 15:33

2 Answers2

3

This is an old question, but I have ran into it quite a few times and only now got it to work right. Here is the relevant bit.

import win32api
import win32con
import win32gui

fuchsia = (255, 0, 128)  # Transparency color
hwnd = pygame.display.get_wm_info()["window"] # Handle
styles = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
styles = win32con.WS_EX_LAYERED | win32con.WS_EX_TRANSPARENT
win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, styles)
win32gui.SetLayeredWindowAttributes(hwnd, win32api.RGB(*fuchsia), 0, win32con.LWA_COLORKEY)
BunnyMerz
  • 133
  • 1
  • 6
  • I've used this successfully as well, there is one interesting caveat. If you have odd shaped windows (not rectangular) and you build them into standalone executable, the empty space that has no alpha information becomes solid again, but it works fine from python env – DCA- Mar 17 '22 at 08:17
2

You will need to do a bit of an extra hacking which is outside what PyGame gives you. It should be possible to render the PyGame canvas into another windowing framework in Python and try to use advanced features of that library to achieve this.

In Windows

One example is wxWidgets. As described in this thread, which sounds quite similar to what you are trying to achieve, the user has setup a window which can be clicked through and is transparent.

Also see this another Stackoverflow Post which mentions how to handle the Hit Testing in C#. Posting code from that post here:

protected override void WndProc(ref Message m)
{
    if (m.Msg == (int)WM_NCHITTEST)
        m.Result = (IntPtr)HTTRANSPARENT;
    else
        base.WndProc(ref m);
}

It is possible to do similar testing in Python using win32 APIs. This is a piece of Python code that does exactly this. Locate the part where the programmer sets up the callback for the event (something like win32con.WM_NCHITTEST: self.onChi, where self.onChi is the callback).

I hope this gives you a starting point. I doubt there is anything readymade that you will find out of the box but these should give you some pointers on what to look for.

Community
  • 1
  • 1
Nandeep Mali
  • 4,456
  • 1
  • 25
  • 34
  • 1
    Thanks, this is very helpful. The thread mentioned contains this line: `win32gui.SetLayeredWindowAttributes(hwnd, 0, 255, win32con.LWA_ALPHA)` which is commented to be the line that handles "click-through". I've got the handle of the pygame window from `py.display.get_wm_info()['window']` but the line throws the error: `win32gui.SetLayeredWindowAttributes(hwnd, 0, 255, win32con.LWA_ALPHA) error: (87, 'SetLayeredWindowAttributes', 'The parameter is incorrect.')`, any thoughts? – DCA- May 24 '16 at 09:39
  • Well, not really, but some ideas: the PyGame window has to be a top level window and make sure it is not a child window, also, make sure the handle that you are getting from pygame is of the correct type to be accepted by SetLayeredWindowAttributes. I will check more once I get to a Windows machine. – Nandeep Mali May 24 '16 at 17:13