Okay, so I am trying to create a Tkinter GUI that is used to control Selenium processes. I want to add a label to the GUI that shows the runtime from the moment I press the start button. What I want is the runtime clock to update itself WHILE the code is running Selenium processes. The problem is that when I press the "Start" button, the runtime clock will update the first second, and will not update again until the Selenium processes are finished. Here is a minimal reproducible example:
NOTE: IF YOU RUN THIS CODE, PLEASE NOTE THE connect_driver() FUNCTION INSTALLS CHOMEDRIVER
import tkinter as tk
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
class GUI():
def __init__(self):
self.root = tk.Tk()
self.root.geometry("200x200")
# run-time clock
self.run_time_label = tk.Label(self.root, text="Run Time:")
self.run_time_label.pack()
self.run_time = tk.Label(self.root, text="00:00:00:00")
self.run_time.pack()
self.run_time_data = {"days":0, "hours":0, "minutes":0, "seconds":0}
# start button
self.start_button = tk.Button(self.root, text="Start", bg="green", height=1, width=10, command=self.start)
self.start_button.pack()
self.root.mainloop()
def start(self):
self.update_runtime()
self.change_state()
self.connect_driver()
self.work()
def stop(self):
driver.close()
driver.quit()
self.change_state()
def update_runtime(self):
if self.run_time_data["seconds"] < 59:
self.run_time_data["seconds"] += 1
elif self.run_time_data["seconds"] == 59:
self.run_time_data["seconds"] = 0
if self.run_time_data["minutes"] < 59:
self.run_time_data["minutes"] += 1
elif self.run_time_data["minutes"] == 59:
self.run_time_data["minutes"] = 0
if self.run_time_data["hours"] < 24:
self.run_time_data["hours"] += 1
elif self.run_time_data["hours"] == 23:
self.run_time_data["hours"] = 0
self.run_time_data["days"] += 1
time_string = "{:02d}:{:02d}:{:02d}:{:02d}".format(self.run_time_data["days"],self.run_time_data["hours"],self.run_time_data["minutes"],self.run_time_data["seconds"])
self.run_time.config(text=time_string)
self.root.after(1000, self.update_runtime)
def change_state(self):
if self.start_button.cget("text") == "Start":
self.start_button.configure(text="Stop", bg="red", command=self.stop)
elif self.start_button.cget("text") == "Stop":
self.start_button.configure(text="Start", bg="green", command=self.start)
self.root.update_idletasks()
def connect_driver(self):
global driver
driver = webdriver.Chrome(ChromeDriverManager().install())
def work(self):
for _ in range(3):
driver.get("http://www.google.com")
driver.get("https://stackoverflow.com")
driver.get("https://www.youtube.com")
if __name__ == "__main__":
app = GUI()
When running this code, as you can see the runtime clock will update to 1 second after pressing "Start", and then continue to do the selenium processes but will not update the runtime clock again until the very end. So I tried to look for a solution to this and figured I would probably need to use Multiprocessing to run the update_runtime() function independently. The problem is, I am very new to Multiprocessing (obviously) and it's not immediately obvious to me how I should use it here. Here is what I tried:
import tkinter as tk
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import multiprocessing as mp
class GUI():
def __init__(self):
self.root = tk.Tk()
self.root.geometry("200x200")
# run-time clock
self.run_time_label = tk.Label(self.root, text="Run Time:")
self.run_time_label.pack()
self.run_time = tk.Label(self.root, text="00:00:00:00")
self.run_time.pack()
self.run_time_data = {"days":0, "hours":0, "minutes":0, "seconds":0}
# start button
self.start_button = tk.Button(self.root, text="Start", bg="green", height=1, width=10, command=self.start)
self.start_button.pack()
self.root.mainloop()
def start(self):
self.process = mp.Process(target=self.update_runtime)
self.process.start()
self.process.join()
self.change_state()
self.connect_driver()
self.work()
def stop(self):
driver.close()
driver.quit()
self.change_state()
def update_runtime(self):
if self.run_time_data["seconds"] < 59:
self.run_time_data["seconds"] += 1
elif self.run_time_data["seconds"] == 59:
self.run_time_data["seconds"] = 0
if self.run_time_data["minutes"] < 59:
self.run_time_data["minutes"] += 1
elif self.run_time_data["minutes"] == 59:
self.run_time_data["minutes"] = 0
if self.run_time_data["hours"] < 24:
self.run_time_data["hours"] += 1
elif self.run_time_data["hours"] == 23:
self.run_time_data["hours"] = 0
self.run_time_data["days"] += 1
time_string = "{:02d}:{:02d}:{:02d}:{:02d}".format(self.run_time_data["days"],self.run_time_data["hours"],self.run_time_data["minutes"],self.run_time_data["seconds"])
self.run_time.config(text=time_string)
self.root.after(1000, self.update_runtime)
def change_state(self):
if self.start_button.cget("text") == "Start":
self.start_button.configure(text="Stop", bg="red", command=self.stop)
elif self.start_button.cget("text") == "Stop":
self.start_button.configure(text="Start", bg="green", command=self.start)
self.root.update_idletasks()
def connect_driver(self):
global driver
driver = webdriver.Chrome(ChromeDriverManager().install())
def work(self):
for _ in range(3):
driver.get("http://www.google.com")
driver.get("https://stackoverflow.com")
driver.get("https://www.youtube.com")
if __name__ == "__main__":
app = GUI()
But when I run this, I get an error : EOFError: Ran out of input
Please please help! :)