Home > other >  How to run Tkinter in the background and update it each time a function executes?
How to run Tkinter in the background and update it each time a function executes?

Time:06-07

I'm writing a script and I'd like to use Tkinter GUI (or any other module which could do this) to show how many times in total this script has been run, store the number in file and update GUI dynamically from this file. But each time I call label.mainloop() nothing past this line gets executed, it just freezes there.

import tkinter
import time


def tracker():    
    f = open('howmanytimes.txt', 'r')
    thenumber = f.read()
    f.close()
    
    tracker = 'Script has run this many times: '   (str(thenumber))
    label = tkinter.Label(text=tracker, font=(
    'Times', '20'), fg='red', bg='black')
    label.master.overrideredirect(True)
    label.master.geometry(" 0 0")
    label.pack()
    label.master.wm_attributes("-topmost", True)   
    label.mainloop()

tracker() # <- Nothing past this line gets executed

time.sleep(2)

i = 0
while i < 20:
    print('Script has been run')
    time.sleep(3)
    
    f = open('howmanytimes.txt', 'w ')
    thenumber = f.read()
    g = int(thenumber)   1
    f.write(str(g))
    f.close()
    
    tracker()
    i =1

CodePudding user response:

Here's a way to implement what you want. I put all the tkinter related code into a class to better encapsulate what it does and allow it to be put into a separate thread. It uses the universal widget method after() to periodically "poll" the file for changes with interfering with tkinter's mainloop() — which is a very common way to do that sort of thing.

I also had to change your file handling quite a bit to get it working and handle all the possible cases of it not existing yet or being empty — as well as deleting it at the end so its existence can't affect a subsequent run of the same program.

import os
from threading import Lock, Thread
import tkinter as tk
import time


class Tracker:
    def __init__(self):
        self.root = tk.Tk()
        self.root.overrideredirect(True)
        self.root.geometry(" 0 0")
        self.root.wm_attributes("-topmost", True)

        # Create empty label widget to be updated.
        self.label = tk.Label(self.root, font=('Times', '20'), fg='red', bg='black')
        self.label.pack()
        self.update()  # Start polling file.
        self.root.mainloop()

    def update(self):
        try:
            with open(FILE_PATH, 'r') as f:
                thenumber = next(f)
        except (FileNotFoundError, StopIteration):
            thenumber = '0'

        self.label.config(text=f'Script has run this many times: {thenumber}')
        with running_lock:
            if running:
                self.label.after(1000, self.update)
            else:
                self.root.quit()  # Stop mainloop.


FILE_PATH = 'howmanytimes.txt'
running_lock = Lock()
running = True
bkg_thread = Thread(target=Tracker)
bkg_thread.start()

for i in range(5):
    try:  # Create or update file.
        with open(FILE_PATH, 'r ') as f:
            thenumber = f.read()
            try:
                g = int(thenumber)   1
            except ValueError:  # Empty file.
                g = 1
            f.seek(0)  # Rewind.
            f.write(str(g))
    except FileNotFoundError:
        with open(FILE_PATH, 'w') as f:
            g = 1
            f.write(str(g))

    print('Script has been run')
    time.sleep(3)

with running_lock:
    running = False  # Tell background thread to stop.

try:
    os.remove(FILE_PATH)  # Clean-up.
except Exception:
    pass

  • Related