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.
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.
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)
Related
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.
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.
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)
A friend and I are making a game in pygame. We would like to have a pygame window embedded into a tkinter or WxPython frame, so that we can include text input, buttons, and dropdown menus that are supported by WX or Tkinter. I have scoured the internet for an answer, but all I have found are people asking the same question, none of these have been well answered.
What would be the best way implement a pygame display embedded into a tkinter or WX frame? (TKinter is preferable)
Any other way in which these features can be included alongside a pygame display would also work.
(Note this solution does not work on Windows systems with Pygame 2.
See Using 'SDL_WINDOWID' does not embed pygame display correctly into another application #1574. You can currently download older versions of Pygame here.)
According to this SO question and the accepted answer, the simplest way to do this would be to use an SDL drawing frame.
This code is the work of SO user Alex Sallons.
import os
import pygame
import Tkinter as tk
from Tkinter import *
root = tk.Tk()
embed = tk.Frame(root, width = 500, height = 500) #creates embed frame for pygame window
embed.grid(columnspan = (600), rowspan = 500) # Adds grid
embed.pack(side = LEFT) #packs window to the left
buttonwin = tk.Frame(root, width = 75, height = 500)
buttonwin.pack(side = LEFT)
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'
screen = pygame.display.set_mode((500,500))
screen.fill(pygame.Color(255,255,255))
pygame.display.init()
pygame.display.update()
def draw():
pygame.draw.circle(screen, (0,0,0), (250,250), 125)
pygame.display.update()
button1 = Button(buttonwin,text = 'Draw', command=draw)
button1.pack(side=LEFT)
root.update()
while True:
pygame.display.update()
root.update()
This code is cross-platform, as long as the windib SDL_VIDEODRIVER line is omitted on non Windows systems. I would suggest
# [...]
import platform
if platform.system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
# [...]
Here are some links.
For embedding in WxPython An Article on pygame.org
For Embedding in WxPython An Article on the WxPython wiki
For embedding in Tkinter see this SO question
Basically, there are many approaches.
On Linux, you can easily embed any application in a frame inside another. Simple.
Direct Pygame output to a WkPython Canvas
Some research will provide the relevant code.
According to the tracebacks, the program crashes due to TclErrors. These are caused by attempting to access the same file, socket, or similar resource in two different threads at the same time. In this case, I believe it is a conflict of screen resources within threads. However, this is not, in fact, due to an internal issue that arises with two gui programs that are meant to function autonomously. The errors are a product of a separate thread calling root.update() when it doesn't need to because the main thread has taken over. This is stopped simply by making the thread call root.update() only when the main thread is not doing so.
A friend and I are making a game in pygame. We would like to have a pygame window embedded into a tkinter or WxPython frame, so that we can include text input, buttons, and dropdown menus that are supported by WX or Tkinter. I have scoured the internet for an answer, but all I have found are people asking the same question, none of these have been well answered.
What would be the best way implement a pygame display embedded into a tkinter or WX frame? (TKinter is preferable)
Any other way in which these features can be included alongside a pygame display would also work.
(Note this solution does not work on Windows systems with Pygame 2.
See Using 'SDL_WINDOWID' does not embed pygame display correctly into another application #1574. You can currently download older versions of Pygame here.)
According to this SO question and the accepted answer, the simplest way to do this would be to use an SDL drawing frame.
This code is the work of SO user Alex Sallons.
import os
import pygame
import Tkinter as tk
from Tkinter import *
root = tk.Tk()
embed = tk.Frame(root, width = 500, height = 500) #creates embed frame for pygame window
embed.grid(columnspan = (600), rowspan = 500) # Adds grid
embed.pack(side = LEFT) #packs window to the left
buttonwin = tk.Frame(root, width = 75, height = 500)
buttonwin.pack(side = LEFT)
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'
screen = pygame.display.set_mode((500,500))
screen.fill(pygame.Color(255,255,255))
pygame.display.init()
pygame.display.update()
def draw():
pygame.draw.circle(screen, (0,0,0), (250,250), 125)
pygame.display.update()
button1 = Button(buttonwin,text = 'Draw', command=draw)
button1.pack(side=LEFT)
root.update()
while True:
pygame.display.update()
root.update()
This code is cross-platform, as long as the windib SDL_VIDEODRIVER line is omitted on non Windows systems. I would suggest
# [...]
import platform
if platform.system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
# [...]
Here are some links.
For embedding in WxPython An Article on pygame.org
For Embedding in WxPython An Article on the WxPython wiki
For embedding in Tkinter see this SO question
Basically, there are many approaches.
On Linux, you can easily embed any application in a frame inside another. Simple.
Direct Pygame output to a WkPython Canvas
Some research will provide the relevant code.
According to the tracebacks, the program crashes due to TclErrors. These are caused by attempting to access the same file, socket, or similar resource in two different threads at the same time. In this case, I believe it is a conflict of screen resources within threads. However, this is not, in fact, due to an internal issue that arises with two gui programs that are meant to function autonomously. The errors are a product of a separate thread calling root.update() when it doesn't need to because the main thread has taken over. This is stopped simply by making the thread call root.update() only when the main thread is not doing so.
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.
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.
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)
When i try to open a borderless mode window it does start in the top right corner of the screen. It looks like this: http://puu.sh/ivB4y/304018da5e.jpg The code looks like this
if __name__ == "__main__":
import source.Game, pygame
pygame.mixer.pre_init(22050, 16, 2, 256)
pygame.font.init()
pygame.init()
screen = pygame.display.set_mode((1920, 1080), pygame.NOFRAME)
source.Game.Game().main(screen)
It might be worth noting that I'm running two monitors, but I've tried only running one and the problem still happens, and if I take the resolution down below native it still won't start in the top right of my screen.
Is there any way to fix such a problem?
EDIT:
I went this from the answers for anyone looking on this in the future.
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = "0,0"
screen = pygame.display.set_mode((1920, 1080), pygame.NOFRAME)
along with all the other .init() statements and whatnot.
Looks like you want fullscreen:
screen = pygame.display.set_mode((1920, 1080), pygame.FULLSCREEN)
You might also want to turn on hardware acceleration adn double buffering using pygame.HWSURFACE | pygame.DOUBLEBUF if you are running fullscreen.
display.set_mode docs: https://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
If you actually want to keep the OS's bar on screen, then instead of going fullscreen, then ideally you would just maximize the window after creating it. However, the version of the SDL lib that Pygame is built on does not support a maximize operation (SDL 2 does). Apparently, you can control the position of the window by setting an environment variable before initializing the window (yuck), but you would still need to figure out the usable area of the desktop. Example:
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = "0,0"
import pygame
pygame.init()
screen = pygame.display.set_mode((100,100))