I'm designing the app in tkinter, I need to read line by line one file each second and view the results on the widgets, also each second. The problem is that my program is reading the whole file and only after this update my Gui.
class Gui(Frame):
def __init__(self, master):
super(Gui, self).__init__()
self.master = master
# ... here are my tkinter widgets
self.ser = None
self.start_update()
def start_update(self):
if self.ser is None:
self.ser = open("serial.txt") # open only once
self.updater()
def updater(self):
while True:
self.raw_line = self.ser.readline()
if self.raw_line:
# here I update labels with .configure() method
self.after(1000, self.updater)
else:
print('Probably end of file')
self.ser.close()
self.ser = None # can open again
root = Tk()
gui = Gui(root)
root.mainloop()
The answer is simple : you have an infinite loop in the main thread that handles the GUI. As a result, the GUI is hanging until the loop is broken.
Here's a simple fix :
class MainWindow(Frame):
def __init__(self, master=None):
super().__init__(master)
self.file = None
self.update_from_file()
self.master.protocol('WM_DELETE_WINDOW', self.on_close)
def open_file(self, filename="serial.txt"):
if self.file is not None:
self.file = open(filename)
def update_from_file(self):
line = self.file.readline()
if line:
# update the widgets
# reminder : when applicable, use tkinter variables
# as they are easier to handle than manually updating with .config()
self.after(1000, self.update_from_file)
def on_close(self):
self.file.close()
self.file = None # can open again
root = Tk()
gui = MainWindow(root)
root.mainloop()
This way, the update_from_file method doesn't hang the main thread while it's processing.
Another option that is valid if you need the extra CPU headroom is to create a separate thread with threading
, and use that to read from the file. This won't hang the tkinter thread either, since both threads are separated. You'll have to be careful with race conditions though if you intend on editing the file as it is open.