Skip to content
Advertisement

Using Tkinter, Threading and After method

im working on a selenium project using tkinter in python. I want to execute many selenium task at one time(could be up to 100), so I used threading to accomplish this goal, but I came to a problem, due to the fact that I need all individual selenium task to wait a couple seconds between instructions, I used the ‘.after’ method but for some reason my program is still freezing up, I’ve done a lot of research but I cant seem to find the answer yet. Isn’t there a way to use tkinter, threading and some sort of sleeping in python? Do I need to switch to multiprocessing? but I would need all selenium processes to finish within the same 2 minutes and each process takes about a minute.(e.g lets say i start 100, 1 minute processes at 6:00 all task would need to be finished by 6:02)

I created minimal code which mimics my selenium script, so its easier to read, here it is:

from tkinter import *
import tkinter as tk
import time
root = tk.Tk()
root.geometry('700x700')
import threading
class Make:
    def __init__(self,num):
        self.num = num.get()
        Label(root,text='HELLO WORLD WILL PRINT: '+str(self.num)+' times, press go to confirm').pack()
        Button(root, text='go', command=lambda: self.starting()).pack()

    def starting(self):

        for count in range(self.num):
            t = threading.Thread(target=gogogo())
            t.start()

def gogogo():
    tk.Label(root,text='HELLO WORLD').pack()
    root.after(2000,print('Please wait 2 seconds'))
    tk.Label(root,text='You are inside my world').pack()


Label(root,text='How many times should I print: HELLO WORLD').pack()

num = IntVar()
Entry(root, textvariable=num).pack()

Button(root, text='Start', command=lambda: Make(num)).pack()

root.mainloop()

Advertisement

Answer

You main problem is that after() and Thread() similar to command= needs only function’s name without () and it will later use () to execute it.

Other problem is that after() doesn’t stop code but it only send information to mainloop to execute function after 2000ms and later Python runs at once next line after after(). You have to add Label in fucntion executed by after()

def gogogo():
    tk.Label(root, text='HELLO WORLD').pack()
    print('Please wait 2 seconds')
    root.after(2000, next_message) # function's name without ()

def next_message():
    tk.Label(root, text='You are inside my world').pack()

# from tkinter import * # PEP8: `import *` is not preferred
import tkinter as tk
import threading
import time

class Make:

    def __init__(self, num):
        self.num = num.get()

        text = 'HELLO WORLD WILL PRINT: {} times, press go to confirm'.format(self.num)
        tk.Label(root, text=text).pack()

        tk.Button(root, text='go', command=self.starting).pack()

    def starting(self):
        for count in range(self.num):
            t = threading.Thread(target=gogogo) # function's name without ()
            t.start()

def gogogo():
    tk.Label(root, text='HELLO WORLD').pack()
    print('Please wait 2 seconds')
    root.after(2000, next_message) # function's name without ()

def next_message():
    tk.Label(root, text='You are inside my world').pack()

# --- main ---

root = tk.Tk()
root.geometry('700x700')

tk.Label(root, text='How many times should I print: HELLO WORLD').pack()

num = tk.IntVar()
tk.Entry(root, textvariable=num).pack()

tk.Button(root, text='Start', command=lambda:Make(num)).pack()

root.mainloop()

EDIT: Because gogogo() runs in separated thread so you can also use time.sleep() because it doesn’t block mainloop() in main thread

def gogogo():
    tk.Label(root, text='HELLO WORLD').pack()
    print('Please wait 2 seconds')
    time.sleep(2)
    tk.Label(root, text='You are inside my world').pack()
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement