Pygame set window on top without changing it's position - python

As I found in the following topic : How to make python window run as "Always On Top"?
I know how to put a window on top. But I would like to keep it at the same position. The autor says that he found a work around to find the x and y values. I would like to know how I can achieve that !
How can I get the x, y values of a pygame window ? Maybe it's a wrong way of doing.
The effect I am looking for is that the window goes on top when I trigger it with some function call.
For those who know League of legends, when a game starts, the window goes on top and remains at the same coordinates.

There's a shorter solution using the same function:
from ctypes import windll
SetWindowPos = windll.user32.SetWindowPos
NOSIZE = 1
NOMOVE = 2
TOPMOST = -1
NOT_TOPMOST = -2
def alwaysOnTop(yesOrNo):
zorder = (NOT_TOPMOST, TOPMOST)[yesOrNo] # choose a flag according to bool
hwnd = pygame.display.get_wm_info()['window'] # handle to the window
SetWindowPos(hwnd, zorder, 0, 0, 0, 0, NOMOVE|NOSIZE)

I found a solution that seems pretty well done:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from ctypes import windll, Structure, c_long, byref #windows only
class RECT(Structure):
_fields_ = [
('left', c_long),
('top', c_long),
('right', c_long),
('bottom', c_long),
]
def width(self): return self.right - self.left
def height(self): return self.bottom - self.top
def onTop(window):
SetWindowPos = windll.user32.SetWindowPos
GetWindowRect = windll.user32.GetWindowRect
rc = RECT()
GetWindowRect(window, byref(rc))
SetWindowPos(window, -1, rc.left, rc.top, 0, 0, 0x0001)
Now in order to put a window on top, simply call onTop(pygame.display.get_wm_info()['window']) to handle your pygame window.

This worked for me
import win32gui
import win32con
win32gui.SetWindowPos(pygame.display.get_wm_info()['window'], win32con.HWND_TOPMOST, 0,0,0,0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
The window doesn't move because I used the SWP_NOMOVE tag

Getting current window position:
from ctypes import POINTER, WINFUNCTYPE, windll
from ctypes.wintypes import BOOL, HWND, RECT
# get our window ID:
hwnd = pygame.display.get_wm_info()["window"]
# Jump through all the ctypes hoops:
prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
paramflags = (1, "hwnd"), (2, "lprect")
GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
# finally get our data!
rect = GetWindowRect(hwnd)
print "top, left, bottom, right: ", rect.top, rect.left, rect.bottom, rect.right
# bottom, top, left, right: 644 98 124 644
Putting the window on the foreground:
x = rect.left
y = rect.top
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (x,y)

I am using a Windows 11 system with Python 3.11.2 and for some reason, the SetWindowPos from windll.user32 library does not work. However the same SetWindowPos function from win32gui library works perfectly. Just do the exact answer #ZiyadCodes gave earlier.
To install required libraries:
$ pip install win32gui
$ pip install win32con
To keep pygame window always on top:
import win32gui
from win32con import SetWindowPos
SetWindowPos(pygame.display.get_wm_info()['window'], win32con.HWND_TOPMOST, 0,0,0,0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)

Related

Make tkinter window always on back

I am trying to make a desktop overlay for windows.
Here is my code:
from tkinter import *
from win32gui import SetWindowPos
from win32con import *
from win32api import Sleep
from threading import Thread
class Desktop:
def Desktop(self):
self.desktoptk = Tk()
tk = self.desktoptk
tk.overrideredirect(True)
tk.geometry(f'{tk.winfo_screenwidth()}x{tk.winfo_screenheight()}+0+0')
def sendtoback():
hwnd = tk.winfo_id()
print(hwnd)
def send():
while True:
Sleep(10)
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)
Thread(target=send).start()
tk.after(200, sendtoback)
bg = PhotoImage(file=R'data\bg.png')
Bg = Label(image=bg)
Bg.image = bg
Bg.place(x=0, y=0)
tk.mainloop()
Desktop().Desktop()
I didn't found anything in the internet what helps me, and i haven't come up with a solution.
I need to make my window to be always on back (opposite of always on top).

How do I always keep pygame window on top of screen regardless of clicking anywhere? [duplicate]

As I found in the following topic : How to make python window run as "Always On Top"?
I know how to put a window on top. But I would like to keep it at the same position. The autor says that he found a work around to find the x and y values. I would like to know how I can achieve that !
How can I get the x, y values of a pygame window ? Maybe it's a wrong way of doing.
The effect I am looking for is that the window goes on top when I trigger it with some function call.
For those who know League of legends, when a game starts, the window goes on top and remains at the same coordinates.
There's a shorter solution using the same function:
from ctypes import windll
SetWindowPos = windll.user32.SetWindowPos
NOSIZE = 1
NOMOVE = 2
TOPMOST = -1
NOT_TOPMOST = -2
def alwaysOnTop(yesOrNo):
zorder = (NOT_TOPMOST, TOPMOST)[yesOrNo] # choose a flag according to bool
hwnd = pygame.display.get_wm_info()['window'] # handle to the window
SetWindowPos(hwnd, zorder, 0, 0, 0, 0, NOMOVE|NOSIZE)
I found a solution that seems pretty well done:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from ctypes import windll, Structure, c_long, byref #windows only
class RECT(Structure):
_fields_ = [
('left', c_long),
('top', c_long),
('right', c_long),
('bottom', c_long),
]
def width(self): return self.right - self.left
def height(self): return self.bottom - self.top
def onTop(window):
SetWindowPos = windll.user32.SetWindowPos
GetWindowRect = windll.user32.GetWindowRect
rc = RECT()
GetWindowRect(window, byref(rc))
SetWindowPos(window, -1, rc.left, rc.top, 0, 0, 0x0001)
Now in order to put a window on top, simply call onTop(pygame.display.get_wm_info()['window']) to handle your pygame window.
This worked for me
import win32gui
import win32con
win32gui.SetWindowPos(pygame.display.get_wm_info()['window'], win32con.HWND_TOPMOST, 0,0,0,0, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
The window doesn't move because I used the SWP_NOMOVE tag
Getting current window position:
from ctypes import POINTER, WINFUNCTYPE, windll
from ctypes.wintypes import BOOL, HWND, RECT
# get our window ID:
hwnd = pygame.display.get_wm_info()["window"]
# Jump through all the ctypes hoops:
prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
paramflags = (1, "hwnd"), (2, "lprect")
GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
# finally get our data!
rect = GetWindowRect(hwnd)
print "top, left, bottom, right: ", rect.top, rect.left, rect.bottom, rect.right
# bottom, top, left, right: 644 98 124 644
Putting the window on the foreground:
x = rect.left
y = rect.top
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (x,y)

Get windows, move and resize on Windows

I'm on Windows and I need to get one window by title name then move and resize it. The code below is for unix only because fcntl doesn't exist on Windows.
import Xlib
import Xlib.display
display = Xlib.display.Display()
screen = display.screen()
root = screen.root
tree = root.query_tree()
wins = tree.children
for win in wins:
print (win.get_wm_name())
win.configure(x=123, y=345, width=678, height=910)
win.change_attributes(win_gravity=X.NorthWestGravity, bit_gravity=X.StaticGravity)
ModuleNotFoundError: No module named 'fcntl'
Do you have an alternative to this please ? Then how to get the windows which has the title "Hello there" ?
I have found this and it is working :
import win32gui, win32con
win2find = 'Skype'
whnd = win32gui.FindWindowEx(None, None, None, win2find)
if not (whnd == 0):
print('Skype')
win32gui.SetWindowPos(whnd, win32con.HWND_NOTOPMOST, 0, 0, 500, 600, 0)

Tkinter see through window not affected by mouse clicks

I am currently controlling a game with python by sending mouse and keystroke commands. What I am looking to do is have a transparent Tkinter window lay overtop of the game to provide some information such as mouse location and pixel color.
I am familiar with changing the window's alpha attribute to make it transparent but have no idea how to always keep that window in front and have mouse clicks pass through it.
My current method of controlling the game involves taking screenshots in certain locations and analyzing the color content. I will also need some way to do this without the Tkinter window interfering.
Pyscreenshot is used for screenshots
win32api is used for clicking
Thank you,
Alec
you can use the SetWindowLong function of win32gui module. If you want a transparent click through window you have to apply GWL_EXSTYLE's ony our window. Therefore you need the windowhandle of your Window.
hwnd = win32gui.FindWindow(None, "Your window title") # Getting window handle
# hwnd = root.winfo_id() getting hwnd with Tkinter windows
# hwnd = root.GetHandle() getting hwnd with wx windows
lExStyle = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
lExStyle |= win32con.WS_EX_TRANSPARENT | win32con.WS_EX_LAYERED
win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE , lExStyle )
If you want to change the transparency of your window via winapi use SetLayeredWindowAttributes.
EDIT: Examplecode for an overlay always-on-top transparent window, which pass through clicks. It gets the current desktopimage and creates a transparent overlay, so you can enjoy your desktop background image.
from win32api import GetSystemMetrics
import win32con
import win32gui
import wx
def scale_bitmap(bitmap, width, height):
image = wx.ImageFromBitmap(bitmap)
image = image.Scale(width, height, wx.IMAGE_QUALITY_HIGH)
result = wx.BitmapFromImage(image)
return result
app = wx.App()
trans = 50
# create a window/frame, no parent, -1 is default ID
# change the size of the frame to fit the backgound images
frame1 = wx.Frame(None, -1, "KEA", style=wx.CLIP_CHILDREN | wx.STAY_ON_TOP)
# create the class instance
frame1.ShowFullScreen(True)
image_file = win32gui.SystemParametersInfo(win32con.SPI_GETDESKWALLPAPER,0,0)
bmp1 = wx.Image(image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
bmp1 = scale_bitmap(bmp1,GetSystemMetrics(1)*1.5,GetSystemMetrics(1))
bitmap1 = wx.StaticBitmap(frame1, -1, bmp1, (-100, 0))
hwnd = frame1.GetHandle()
extendedStyleSettings = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, extendedStyleSettings | win32con.WS_EX_LAYERED | win32con.WS_EX_TRANSPARENT)
win32gui.SetLayeredWindowAttributes(hwnd, 0, 255, win32con.LWA_ALPHA)
frame1.SetTransparent(trans)
def onKeyDown(e):
global trans
key = e.GetKeyCode()
if key==wx.WXK_UP:
print trans
trans+=10
if trans >255:
trans = 255
elif key==wx.WXK_DOWN:
print trans
trans-=10
if trans < 0:
trans = 0
try:
win32gui.SetLayeredWindowAttributes(hwnd, 0, trans, win32con.LWA_ALPHA)
except:
pass
frame1.Bind(wx.EVT_KEY_DOWN, onKeyDown)
app.MainLoop()
You can dynamically change the transparency with the arrow keys Up/Down.
Notice, the windowframe is created with 'wx', but should work with tkinter also.
Feel free to use the code as you like.

Python screenshot 2+ monitors (windows)

How to make a screenshot with python, if connected to multiple monitors?
I tried:
import sys
from PyQt4.QtGui import QPixmap, QApplication
app = QApplication(sys.argv)
QPixmap.grabWindow(QApplication.desktop().winId()).save('test.png', 'png')
import ImageGrab
im = ImageGrab.grab()
im.save('test.png', 'PNG')
Both options provide a screenshot, only the primary monitor
If I use winapi:
hWnd = win32gui.FindWindow(None, win_name)
dc = win32gui.GetWindowDC(hWnd)
i_colour = int(win32gui.GetPixel(dc,int(x),int(y)))
rgb = ((i_colour & 0xff), ((i_colour >> 8) & 0xff), ((i_colour >> 16) & 0xff))
I get a picture from a window in the second monitor. But it will be very slow.
If I press key 'printscreen' in the clipboard will be a normal screenshot, with all monitors. Is there a option to get a Full screenshot in Python?
My Desktopmagic library provides this functionality for Python 2.6, 2.7, and 3.3+. It can return a PIL/Pillow Image or write a BMP.
Using a mix of wxPython, win32api and ctypes:
import wx, win32api, win32gui, win32con, ctypes
class App(wx.App):
def OnInit(self):
dll = ctypes.WinDLL('gdi32.dll')
for idx, (hMon, hDC, (left, top, right, bottom)) in enumerate(win32api.EnumDisplayMonitors(None, None)):
hDeskDC = win32gui.CreateDC(win32api.GetMonitorInfo(hMon)['Device'], None, None)
bitmap = wx.EmptyBitmap(right - left, bottom - top)
hMemDC = wx.MemoryDC()
hMemDC.SelectObject(bitmap)
try:
dll.BitBlt(hMemDC.GetHDC(), 0, 0, right - left, bottom - top, int(hDeskDC), 0, 0, win32con.SRCCOPY)
finally:
hMemDC.SelectObject(wx.NullBitmap)
bitmap.SaveFile('screenshot_%02d.bmp' % idx, wx.BITMAP_TYPE_BMP)
win32gui.ReleaseDC(win32gui.GetDesktopWindow(), hDeskDC)
return False
App(0)
install desktopmagic:
pip install Desktopmagic)
from __future__ import print_function
import desktopmagic
from desktopmagic.screengrab_win32 \
import(getDisplayRects,saveScreenToBmp,getScreenAsImage,getRectAsImage,getDisplaysAsImages)
""" getDisplayRects functions returns a list with all displays, in display order, like [(0, 0, 1280, 1024), (-1280, 0, 0, 1024), (1280, -176, 3200, 1024)] : (left, top, right, bottom)"""
screens=(getDisplayRects())
take a screenshot of the second monitor
rect = getRectAsImage(screens[1])
0 for the first display 1 for the second and ...
#saves screenshot
rect.save('leftscr.png',format='png')

Categories

Resources