[Python] How to make a fully click-through watermark window in Tkinter?

Discussão em 'Python' iniciado por Stack, Janeiro 22, 2025.

  1. Stack

    Stack Membro Participativo

    I'm trying to create a transparent watermark overlay using Tkinter that displays system information (hostname, username, IP, and time) on all monitors. The watermark updates every second and should not interfere with user interaction at all.

    Issues I'm Facing: The window captures mouse clicks, preventing interaction with applications beneath it. The text sometimes interferes with interaction, meaning it's not always fully transparent.

    import socket
    import psutil
    import tkinter as tk
    from datetime import datetime
    from screeninfo import get_monitors

    def get_system_info():
    hostname = socket.gethostname()
    user = psutil.users()[0].name
    ip = socket.gethostbyname(hostname)
    current_time = datetime.now().strftime("%y-%m-%d %H:%M")
    return f"{hostname},{current_time}, {user} "



    def display_watermark(text):
    windows = []
    for monitor in get_monitors():
    root = tk.Tk()
    root.overrideredirect(True)
    root.attributes("-topmost", True)
    root.attributes("-alpha", 0.3)
    root.geometry(f"{monitor.width}x{monitor.height}+{monitor.x}+{monitor.y}")
    root.config(bg="black")
    root.wm_attributes("-transparentcolor", "#000000")

    root.protocol("WM_DELETE_WINDOW", lambda: None)
    canvas = tk.Canvas(root, width=monitor.width, height=monitor.height, bg="black", highlightthickness=0)
    canvas.pack(fill="both", expand=True)

    for y in range(-50, monitor.height + 100, 400):
    for x in range(-100, monitor.width + 200, 800):
    canvas.create_text(x, y, text=text, font=("Arial", 28), fill="gray", angle=45)

    windows.append((root, canvas, monitor))

    def update_text():
    new_text = get_system_info()
    for window, canvas, monitor in windows:
    canvas.delete("all")
    for y in range(-50, monitor.height + 100, 400):
    for x in range(-100, monitor.width + 200, 800):
    canvas.create_text(x, y, text=new_text, font=("Arial", 28), fill="gray", angle=45)
    root.after(1000, update_text)

    update_text()
    for window, _, _ in windows:
    window.mainloop()

    system_info_text = get_system_info()
    display_watermark(system_info_text)


    I tried to solve it in the following way

    root.attributes("-alpha", 0.3) – makes the window semi-transparent but still blocks clicks. root.wm_attributes("-transparentcolor", "#000000") – makes the background transparent, but the text still captures clicks. root.attributes("-disabled", True) – disables the window but also prevents updating the watermark text. Using root.lower() and root.attributes("-topmost", False), but then the watermark gets hidden behind other windows.

    import socket
    import psutil
    import tkinter as tk
    from datetime import datetime
    from screeninfo import get_monitors
    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 get_system_info():

    hostname = socket.gethostname()
    user = psutil.users()[0].name
    current_time = datetime.now().strftime("%y-%m-%d %H:%M")
    return f"{hostname}, {current_time}, {user}"


    def display_watermark():

    monitors = get_monitors()


    min_x = min(m.x for m in monitors)
    min_y = min(m.y for m in monitors)
    max_width = sum(m.width for m in monitors)
    max_height = max(m.y + m.height for m in monitors) - min_y


    root = tk.Tk()
    root.overrideredirect(True)
    root.attributes("-topmost", True)
    root.attributes("-alpha", 0.3)
    root.geometry(f"{max_width}x{max_height}+{min_x}+{min_y}")
    root.config(bg="black")
    root.wm_attributes("-transparentcolor", "#000000")

    canvas = tk.Canvas(root, width=max_width, height=max_height, bg="black", highlightthickness=0)

    setClickthrough(canvas)
    canvas.pack(fill="both", expand=True)

    def update_text():
    new_text = get_system_info()
    canvas.delete("all")


    for y in range(-50, max_height + 100, 400):
    for x in range(-100, max_width + 200, 800):
    canvas.create_text(x, y, text=new_text, font=("Arial", 28), fill="gray", angle=45)

    root.after(1000, update_text)

    update_text()
    root.mainloop()


    display_watermark()



    The watermark should be completely click-through (no interaction blocking). The text should also be transparent and not interfere with mouse clicks. How can I ensure that the entire window, including the text, is completely click-through?

    Continue reading...

Compartilhe esta Página