5

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

Alec Mitchell
  • 53
  • 1
  • 6

1 Answers1

4

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.

VRage
  • 1,458
  • 1
  • 15
  • 27
  • Will this only allow mouse clicks to pass through to other windows in the same tk instance? I'm asking because I applied this to my root window, and I am unable to click on or drag other windows (ex Chrome). – sawyermclane Apr 17 '18 at 19:30
  • This should actually work. I've wrote a little script which places my desktop background image as transparent topmost window over all other windows. And this worked as intended, all click gone through and drag&drop also worked. – VRage Apr 18 '18 at 13:27
  • But you can also try to handle `WM_NCHITTEST` and returning `HTNOWHERE` – VRage Apr 18 '18 at 13:46
  • How do I do that? – sawyermclane Apr 19 '18 at 20:09
  • I think this link will help you: https://stackoverflow.com/questions/37166320/pygame-allow-clicks-to-go-through-the-window/37372476 – VRage Apr 20 '18 at 05:36
  • I tried the methods at that link that would work in Python and tk, to no avail. – sawyermclane Apr 23 '18 at 03:48
  • 2
    Well it's hard to give useful help if your code is unkown to me... I suggest you to create a Question with reproduceable code – VRage Apr 23 '18 at 05:26
  • @VRage Sorry for digging in an old thread, but when tried on a tkinter window, I only get a completely invisible screen which doesn't allow click through. [HERE](https://paste.atilla.org/paste/748WRW) is the small reproducible code I have tried. Py3.7, Windows10. I'll appreciate any suggestion. – P S Solanki Nov 17 '20 at 14:00
  • 1
    @PSSolanki It's a very long time since i touched pyhton, but i've coded a small app which is capable of what you need. Be aware its wxpython and pyhton 2.7. I think i used wx because tk got some problems with images ... but its to long ago to remember correctly – VRage Nov 17 '20 at 18:13
  • Amazing. Thank you so much :) That helps. – P S Solanki Nov 18 '20 at 05:49
  • Big help, thank you so much! Still works today, first try right after `pip install wxpython` :) – Eric Carmichael Oct 12 '21 at 09:33