Reputation: 865
I've been looking through Python GUI libs such as Tkinter
, kivy
and pygame
for a way to make a transparent window with Opaque assets (such as a button or a sprite) so that only the window is transparent letting me see whats behind it, but the button, image etc is still solid appearing to float in mid air.
In the case example of the sprite image, it would look like only the sprite is floating on the screen with no bordering window, box etc.
Tkinter
has attributes('-alpha',07)
but this is applied to all assets.
kivy
has a background_color
which affects opacity but 0 doesn't make it transparent only grey.
From what I have read this appears to be a difficult problem and possibly requires OS level changes, some related stack questions with no answers linked here and here.
but I wanted to ask if anyone had a potential solution?
Upvotes: 1
Views: 1785
Reputation: 7886
Note: Only works on windows. I am looking into other OSs, but there is not standard cross-platform solution as far as I can tell. You will always have to find a solution on a C level and adapt it to something you can use from python.
I create a small package and shared it on github. Look at test_pkg.py for a small example on how to use. Currently, the package implements the below solution for windows and another using the Shape Extension for X11 based systems.
If you want the entire window to become invisible except for a few parts, without blending with the background, you can use SetLayeredWindowAttributes
as mentioned in this answer. I am showing the code for pygame
, but similar stuff should also be possible with other libraries.
The important parts of the windows C interface are here:
import pygame
import ctypes
from ctypes import windll, WINFUNCTYPE
from ctypes import wintypes
prototype = WINFUNCTYPE(
wintypes.BOOL,
wintypes.HWND,
wintypes.COLORREF,
wintypes.BYTE,
wintypes.DWORD
)
paramflags = (1, "hwnd"), (1, "crKey"), (1, "bAlpha"), (1, "dwFlags")
SetLayeredWindowAttributes = prototype(("SetLayeredWindowAttributes", windll.user32), paramflags)
prototype = WINFUNCTYPE(
wintypes.LONG,
wintypes.HWND,
ctypes.c_int,
wintypes.LONG,
)
paramflags = (1, "hwnd"), (1, "nIndex"), (1, "dwNewLong")
SetWindowLongA = prototype(("SetWindowLongA", windll.user32), paramflags)
prototype = WINFUNCTYPE(
wintypes.LONG,
wintypes.HWND,
ctypes.c_int,
)
paramflags = (1, "hwnd"), (1, "nIndex")
GetWindowLongA = prototype(("GetWindowLongA", windll.user32), paramflags)
GWL_EXSTYLE = -20
WS_EX_LAYERED = 0x00080000
LWA_ALPHA = 0x2
LWA_COLORKEY = 0x1
def get_handle():
wm_info = pygame.display.get_wm_info()
return wm_info["window"]
It can then be used like this:
INVISIBLE = 255, 0, 255
# Window has to have been created at this point
hwnd = pygame.display.get_wm_info()["window"]
SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED)
SetLayeredWindowAttributes(hwnd, wintypes.RGB(*INVISIBLE), 0, LWA_COLORKEY)
This will make everything colored exactly INVISIBLE
not be drawn. You can also use some other random color (or black if you want) instead of the 'error pink' I am using.
Note that you probably also want to use pygame.NOFRAME
as flag for set_mode
to not render the border. Note that you can't access the close button then.
Upvotes: 1