-2

I have created a script which constantly screenshots and finds elements on the screen, and I want to use tkinter or a similar framework to overlay text on the screen. The main script runs in a while loop and checks every x seconds, and I want the tkinter window to also update ever x seconds until the script is closed.

import tkinter as tk
from pynput import keyboard

def superimpose_text(text):
    color = "black" if isinstance(text, str) else 'green' if text < 10 else 'yellow' if text < 15 else 'red'
    label = tk.Label(root, text=text, font=('Times New Roman', '50'), fg=color, bg='white')
    label.lift()
    root.geometry("+1400+600")
    root.wm_attributes("-topmost", True)
    root.wm_attributes("-disabled", True)
    root.wm_attributes("-transparentcolor", "white")
    label.pack()

    listener = keyboard.Listener(on_press=lambda event: root.destroy())
    listener.start()

while True:
    root = tk.Tk()
    text = screenshot_info()
    superimpose_text(text)
    root.mainloop()

Currently I'm using a listener to destroy the label at any keypress, as that's the only way I can get It to ever update the text, but this isn't working. How do i make it continuously update every time the while loop runs?

JRiggles
  • 4,847
  • 1
  • 12
  • 27

1 Answers1

1

Take the declaration of root = tk.Tk() and root.mainloop() out of the while loop - tkinter runs its own GUI event loop anyway, so it's handled for you. Then, wrap the calls to text = screenshot_info() and superimpose_text(text) into a function (ex. def update_text()) that calls itself again using after(), e.g. after(100, update_text). To start the updates, just call update_text() as normal.

import tkinter as tk


# instantiate Tk and set the window properties here
root = tk.Tk()
root.geometry("+1400+600")
root.wm_attributes("-topmost", True)
root.wm_attributes("-disabled", True)
root.wm_attributes("-transparentcolor", "white")

label = tk.Label(
    root, 
    text='', 
    font=('Times New Roman', '50'),
    fg='black', 
    bg='white',
)
label.pack()


def superimpose_text(text):
    color = "black" if isinstance(text, str) else 'green' if text < 10 else 'yellow' if text < 15 else 'red'
    # update the label
    label.config(text=text, fg=color)


def update_text():
    text = screenshot_info()
    superimpose_text(text)
    root.after(100, update_text)  # have this func call itself again every 100mS


update_text()  # start the update loop
root.mainloop()

There are some issues with how you're setting color, but I'm going to leave that to you.

JRiggles
  • 4,847
  • 1
  • 12
  • 27
  • 1
    The code still stops after i press a button, it doesn't continue to run – Tobias Christensen Jun 09 '23 at 12:14
  • It doesn't work, man – toyota Supra Jun 09 '23 at 12:15
  • You're calling `root.destroy()` on keyboard presses - what did you expect to happen? – JRiggles Jun 09 '23 at 12:16
  • line 14, in listener = keyboard.Listener(on_press=lambda event: root.destroy()) ^^^^^^^^^^^^^^ – toyota Supra Jun 09 '23 at 12:17
  • Also, setting `root` properties like `geometry` shouldn't be handled inside a function like that if you don't actually need to set/update them more than once. I'll edit my answer to reflect this. – JRiggles Jun 09 '23 at 12:18
  • And another important point regarding the keybinding: tkinter has built-in functionality for this, e.g.: `root.bind('' , lambda _event: callback_function())`, which is to say you probably don't need `pynput` – JRiggles Jun 09 '23 at 12:24
  • So I read through your question again and it sounds to me like you don't need the keypress event at all if it was just a workaround for getting the text to update. I'm going to remove that code from this answer. – JRiggles Jun 09 '23 at 12:29
  • Yeah the keypress was just a means to make it "work", and the solution you have made is close, but it doesn't overwrite the current text, it makes a new text block, can it be made to overwrite the old text? – Tobias Christensen Jun 09 '23 at 13:34
  • Should be fixed now. The idea is to create the `Label` once, and then update it as needed – JRiggles Jun 09 '23 at 13:41
  • Thank you, this is so good! The one issue with it is that the tkinter window is visible for this version, it wasn't in my original version, but I cannot even see why its different. Thanks though, will marked as solved – Tobias Christensen Jun 09 '23 at 14:15
  • You may need to set the color of your `root` window to match your `-transparentcolor`, i.e. `'white'` – JRiggles Jun 09 '23 at 14:25
  • That does remove the background of the tkinter window but not the border of the window with the topbar – Tobias Christensen Jun 09 '23 at 14:36
  • i added "label.master.overrideredirect(True)" which works! – Tobias Christensen Jun 09 '23 at 14:39
  • You can just use `root.overrideredirect(True)` since `root` is the `master` of your `label` – JRiggles Jun 09 '23 at 15:03