osdir.com

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

How to run an infinite loop on Menu?


huey.y.jiang at gmail.com wrote:

> Hi Folks,
> 
> I need to run an infinite loop on a Menu button, like this:
> 
> from Tkinter import *
> 
> def run_job():
>     i = 0
>     while 1:
>         i = i + 1
>         if i > 100:
>             break
>      .......
> 
> root = Tk()
> menu = Menu(root)
> root.config(menu=menu)
> filemenu = Menu(menu)
> menu.add_cascade(label="Jobs", menu=filemenu)
> filemenu.add_command(label="Run", command=run_job)
> mainloop()
> 
> 
> In fact, the def run_job has more things to do. But, it is an infinite
> loop in essence. It works. However, when the def run_job is running, the
> menu will be hang there. I have no way to stop it. Even if I raise it with
> Key-Interupt, the thing was the same: the infinite loop cannot be stopped
> nicely. The only way was to wait until the Python interpreter notice the
> problem, and popped out an error message, then I can kill the running
> program.
> 
> Can anybody tell me how to handle this? I wish when variable i reached
> 100, the run_job will be end, and the Menu "Run" will be free.
> 
> Thanks in advance.

You need to break your loop into smaller steps and after each step give the 
user interface a chance to run.

Here's a fancy way using a generator. run_job() implements the steps and 
after each yield next_step() will schedule itself for reinvocation after 100 
milliseconds.

from Tkinter import *

def run_job():
    i = 0
    while True:
        status("i = {}".format(i))
        i = i + 1
        if i > 100:
            break
        yield

def start_job():
    global steps

    status("starting")
    filemenu.entryconfig("Run", state=DISABLED)
    steps = run_job()
    next_step()

def next_step():
    try:
        next(steps)
    except StopIteration:
        status("done")
        filemenu.entryconfig("Run", state=NORMAL)
    else:
        root.after(100, next_step)

def status(message):
    status_label["text"] = message
    print(message)

root = Tk()
menu = Menu(root)
root.config(menu=menu)
root.minsize(100, 50)
filemenu = Menu(menu)
menu.add_cascade(label="Jobs", menu=filemenu)
filemenu.add_command(label="Run", command=start_job)

status_label = Label(root)
status_label.pack()

root.mainloop()