点击 tkinter 窗口进行穿透

4

这个函数是从Tying to set non-interactable (click-through) overlay with TkInter中复制的。

不仅窗口不能穿透,PNG 图片也不透明。 PNG 图片在这里:https://drive.google.com/file/d/1tlLl2hjPq38mc_c_PpMhkKDlP1HqvDY5/view

这是窗口的样子:

窗口截图

我错过了什么?

from tkinter import*
import win32gui

from win32gui import GetForegroundWindow, ShowWindow, FindWindow, SetWindowLong, GetWindowLong, SetLayeredWindowAttributes
from win32con import SW_MINIMIZE, WS_EX_LAYERED, WS_EX_TRANSPARENT, GWL_EXSTYLE

def setClickthrough(hwnd):
   try:
       styles = GetWindowLong(hwnd, GWL_EXSTYLE)
       styles |= WS_EX_LAYERED | WS_EX_TRANSPARENT
       SetWindowLong(hwnd, GWL_EXSTYLE, styles)
       SetLayeredWindowAttributes(hwnd, 0, 255, win32con.LWA_ALPHA)
   except Exception as e:
       print(e)

root = Tk()
root.geometry("100x100")


root.overrideredirect(1)

root.attributes('-topmost', 1)
pic = PhotoImage(file=r'on2.png')
root.wm_attributes("-transparentcolor", 'white')

boardbutton = Label(root, image=pic, bd=0,
                    bg='white')
boardbutton.pack()
setClickthrough(root.winfo_id())
root.mainloop()
2个回答

6

我拿到了链接的问题的代码并且让它运行起来了。请看下面的代码:

from tkinter import *
from PIL import Image, ImageTk
import win32gui
import win32con

def setClickthrough(hwnd):
    print("setting window properties")
    try:
        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, 0, 255, win32con.LWA_ALPHA)
    except Exception as e:
        print(e)

# Dimensions
width = 1920 #self.winfo_screenwidth()
height = 1080 #self.winfo_screenheight()

root = Tk()
root.geometry('%dx%d' % (width, height))
root.title("Applepie")
root.attributes('-transparentcolor', 'white', '-topmost', 1)
root.config(bg='white') 
root.attributes("-alpha", 0.25)
root.wm_attributes("-topmost", 1)
bg = Canvas(root, width=width, height=height, bg='white')

setClickthrough(bg.winfo_id())

frame = ImageTk.PhotoImage(file="example.png")
bg.create_image(1920/2, 1080/2, image=frame)
bg.pack()
root.mainloop()

重要区别在于使用了画布的hwnd而不是窗口。
我无法完全按照您的要求实现,但是我提供了一些代码,可以输出我所需的内容,并希望满足您的需求。额外的代码仅删除装饰(overrideredirect(1))并将窗口调整为img大小,还将其放置在屏幕中央。

enter image description here

from tkinter import *
from PIL import Image, ImageTk
import win32gui
import win32con

def setClickthrough(hwnd):
    print("setting window properties")
    try:
        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, 0, 255, win32con.LWA_ALPHA)
    except Exception as e:
        print(e)

def size_position_for_picture():
    bbox = bg.bbox(img_id)
    w,h = bbox[2]-bbox[0],bbox[3]-bbox[1]
    x,y = sw/2-w/2,sh/2-h/2
    root.geometry('%dx%d+%d+%d' % (w,h, x,y))
    bg.configure(width=w,height=h)
    

root = Tk()

sw = root.winfo_screenwidth()
sh = root.winfo_screenheight()

root.overrideredirect(1)
root.attributes("-alpha", 0.75)
root.attributes('-transparentcolor', 'white', '-topmost', 1)
bg = Canvas(root,bg='white',highlightthickness=0)
root.config(bg='white')

setClickthrough(bg.winfo_id())

frame = ImageTk.PhotoImage(file="example.png")
img_id = bg.create_image(0,0, image=frame,anchor='nw')
bg.pack()

size_position_for_picture()
setClickthrough(bg.winfo_id())


root.mainloop()

这对我来说起作用了,但是现在即使将"-transparentcolor"设置为透明图像的背景,它也不透明了。 - undefined

3
我也有一个函数在我的应用程序中实现这个功能,代码看起来与你的非常相似,只是有一些小调整。你可以试一下:
def set_clickthrough(hwnd, root):
    # Get window style and perform a 'bitwise or' operation to make the style layered and transparent, achieving
    # the clickthrough property
    l_ex_style = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
    l_ex_style |= win32con.WS_EX_TRANSPARENT | win32con.WS_EX_LAYERED
    win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, l_ex_style)

    # Set the window to be transparent and appear always on top
    win32gui.SetLayeredWindowAttributes(hwnd, win32api.RGB(0, 0, 0), 190, win32con.LWA_ALPHA)  # transparent
    win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, root.winfo_x(), root.winfo_y(), 0, 0, 0)

还有,以下函数可再次禁用点击穿透

def disable_clickthrough(hwnd, root):
    # Calling the function again sets the extended style of the window to zero, reverting to a standard window
    win32api.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, 0)
    # Remove the always on top property again, in case always on top was set to false in options
    win32gui.SetWindowPos(hwnd, win32con.HWND_NOTOPMOST, root.winfo_x(), root.winfo_y(), 0, 0, 0)

您可以通过调用 win32gui.FindWindow(None, root.title()) 来获取窗口句柄(hwnd)。


窗口没有显示,是因为"SetWindowsPos"的"cx=0"和"cy=0"。这些参数需要窗口的宽度和高度。所以我把"SetWindowPos"从win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, root.winfo_x(), root.winfo_y(), 0, 0, 0)改成了win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, root.winfo_x(), root.winfo_y(), root.winfo_width(), root.winfo_height(), 0) - Sniper1999

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接