0

So I have tried extensively to figure out the best way to run my code. The best suggestions have been to run a root.after recursively until a condition is met. This works but it freezes the window until the condition is met. I cannot figure out what is wrong or how to fix this. I would like to display the tkinter dialog window, check every 1000 ms if a condition has been met, once met allow the "NEXT" button to become clickable. This all works except if the condition is never met, there is no way to exit the program because the nav bar is stuck in "not responding". I really need this nav bar to not be messed up. I prefer it over a close button. Here is the code

def checkForPortConnection(root, initial_ports):
    new_ports = listSerialPorts()
    root.after(1000)
    if initial_ports == new_ports:
        checkForPortConnection(root, initial_ports)
    else:
        return
    

def welcomeGui():
    
    root = tk.Tk()
    root.title('Setup Wizard')
    canvas1 = tk.Canvas(root, relief = 'flat')
    welcome_text='Welcome to the setup wizard for your device'
    text2 =  'Please plug your device into a working USB port'
    text3 = 'If you have already plugged it in, please unplug it and restart the wizard. \n Do not plug it in until the wizard starts. \n The "NEXT" button will be clickable once the port is detected'
    label1 = tk.Label(root, text=welcome_text, font=('helvetica', 18), bg='dark green', fg='light green').pack()
    label2 = tk.Label(root, text=text2, font=('times', 14), fg='red').pack()
    label3 = tk.Label(root, text=text3, font=('times', 12)).pack()

    nextButton = ttk.Button(root, text="NEXT", state='disabled')
    nextButton.pack()
    initial_ports = listSerialPorts()
    
    root.update()
    checkForPortConnection(root, initial_ports)
    new_ports = listSerialPorts()
    correct_port = [x for x in initial_ports + new_ports if x not in initial_ports or x not in new_ports]
    print(correct_port)
    nextButton.state(["!disabled"])
    root.mainloop()
Justin Oberle
  • 502
  • 3
  • 22
  • I guess you using `after` in the wrong way, normally you do `root.after(*ms, func)`. After dosent stops your code until the time is up, its more like a coroutine. [Check](https://stackoverflow.com/questions/63118430/create-a-main-loop-with-tkinter/63118515#63118515) The way you did it is more an infint loop that holds on the mainloop till the condition is met. – Thingamabobs Oct 27 '20 at 17:37

1 Answers1

1

root.after(1000) is effectively the same as time.sleep(1) - it freezes the UI until the time has expired. It doesn't allow the event loop to process events.

If you want to call checkForPortConnection every second, this is the proper way to do it:

def checkForPortConnection(root, initial_ports):
    new_ports = listSerialPorts()
    if initial_ports == new_ports:
        root.after(1000, checkForPortConnection, root, initial_ports)

That will call checkForPortConnection one second in the future (more or less), passing root and initial_ports as arguments. Each time it runs, it will schedule itself to be run again in the future until the condition is no longer met.

Until the time period has expired, mainloop is able to continue to process events as normal.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Ok Your solution works. I was going wrong by not calling listSerialPorts in the else statement before the return. Thank you so much!! – Justin Oberle Oct 27 '20 at 20:37