0

I've tried by now several methods found online but I can't seem to find a solution. What I want to create is to enable a while loop with a button and disable it with another button. The main issue, is that while the loop is active, it freezes my GUI when I press my "disable" button. The while loop does stop, but I have to kill the executable in task manager and restart it in order to re-enable the while loop.

Code:

from tkinter import *
import time

top = Tk()
top.title("Corsair")
top.geometry('100x100')
top.resizable(False, False)

def b1(): 
    while True:
        [MY MAIN CODE]
#       if But2.is_pressed:
#           break

but1 = Button(top, image = onbutton, text ="On", command = b1)
but2 = Button(top, image = offbutton, text ="Off", pady = 100, padx = 10, command = top.destroy)

but1.pack()
but2.pack()
top.mainloop()

I've tried; if But2.is_pressed to break the code, which freezes the GUI.

Make but2 to destroy top window, which freezes the GUI.

I've tried ;

x = 1

def b1(): 
    while True:
        if x == 1:
            [MY MAIN CODE]
        else:
            break   

def b2():
    x = 0   

but1 = Button(top, image = onbutton, text ="On", command = b1)
but2 = Button(top, image = offbutton, text ="Off", pady = 100, padx = 10, command = b2)
but3 = Button(top, text ="Exit", pady = 100, padx = 20, command = top.destroy)
Twisted
  • 7
  • 3
  • 2
    This is not how `tkinter` is designed to be used. Please look at [event driven programming](https://en.wikipedia.org/wiki/Event-driven_programming). You shouldn't use `while True` loops in `tkinter` code. – TheLizzard Sep 11 '22 at 12:08
  • Thanks! Guess it's then either freezing the GUI and manual kill the exe or avoid the entire thing all together then? – Twisted Sep 11 '22 at 13:39
  • It's just that you are using `tkinter` incorrectly. Look at some `tkinter` tutorials. – TheLizzard Sep 11 '22 at 13:44
  • this question has been asked before: https://stackoverflow.com/questions/53580507/disable-enable-button-in-tkinter – D.L Sep 11 '22 at 14:28
  • Does this answer your question? [Disable / Enable Button in TKinter](https://stackoverflow.com/questions/53580507/disable-enable-button-in-tkinter) – D.L Sep 11 '22 at 14:28
  • you may have to run loop in separated thread - or you should use `top.after(0, b1)` at the end of `b1` (instead of `while`) to repeate functon after 0 milliseconds – furas Sep 11 '22 at 15:11

1 Answers1

0

This problem was few times on Stackoverflow:

If you run long-running loop then you should run it in separate thread.

But if every loop is not so long then you could use .after(milliseconds, function_name) at the end of function (instead of while and sleep) to repeat function again - and this will work as loop, and tkinter will have time to run own mainloop

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

# --- functions ---  # PEP8: all functions before main code

def b1(): 
    print('MY MAIN CODE')
    if running:
        # repeat after 100ms (0.1s)
        top.after(100, b1)  # funcion's name without ()
    else:
        print('STOP')

def b2(): 
    global running
    
    running = False
    
# --- main ---

running = True

top = tk.Tk()

but1 = tk.Button(top, text="On",  command=b1)   # PEP8: inside `()` use `=` without spaces
but2 = tk.Button(top, text="Off", command=b2)
but1.pack()
but2.pack()

top.mainloop()

EDIT:

If you want to use button On to restart loop again then it may need extra function to set again running = True

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

# --- functions ---  # PEP8: all functions before main code

def b1():
    global running

    running = True
    
    loop()
    
def loop():    
    print('MY MAIN CODE')
    
    if running:
        # repeat after 100ms (0.1s)
        top.after(100, loop)  # funcion's name without ()
    else:
        print('STOP')
        
def b2(): 
    global running
    
    running = False
    
# --- main ---

running = True

top = tk.Tk()

but1 = tk.Button(top, text="On",  command=b1)   # PEP8: inside `()` use `=` without spaces
but2 = tk.Button(top, text="Off", command=b2)
but1.pack()
but2.pack()

top.mainloop()
furas
  • 134,197
  • 12
  • 106
  • 148
  • Awesome! Many thanks! That did the trick! Now the GUI doesn't freeze anymore (well only for a second or two, but I can live with that haha). And many thanks for your additional comments on the code itself! Sure is helpful! Been a bit rusty in Python and sure need to revisit a tutorial or two at least. – Twisted Sep 12 '22 at 10:26
  • If loop runs longer-running code then you may add few `top.update()` between lines - and this will force `tkinter` to get key/mouse events from system, sendt them to widgets and (re)draw widgets in window. – furas Sep 12 '22 at 11:04
  • Sorry a bit late, haven't been logged in for a while. Many thanks! I'll try that out as well and see if it gives the desired effect. – Twisted Sep 27 '22 at 10:16