0

I want to set a function to repeat again again after the message box is shown. A short example of code is shown below that what i exactly want to do

def setInterval(func,time,args):
    e = threading.Event()
    while not e.wait(time):
        func(args)

def foo(data):
    print data
    aa("what")
def aa(a):
    print(a)

tkMessageBox.showinfo("Regret","nope")

setInterval(foo,5,"fsrty")

All things are okay but the problem is only that once the messgae box is shown its give "not responding error".Anyone please help to find out the solution

Lal Rishav
  • 11
  • 2

2 Answers2

2

You will need to use the .after method since threading never work well this tkinter and nor does a while loop.

import Tkinter as tk
import TkMessageBox

def setInterval(func,time,args):
        func(args)
        root.after(time, setInterval(func, time, args))
root.tk.Tk()
root.withdraw()
def foo(data):
    print data
    aa("what")
def aa(a):
    print(a)

tkMessageBox.showinfo("Regret","nope")
setInterval(foo, 5, "fsrty")
root.mainloop()
Taku
  • 31,927
  • 11
  • 74
  • 85
0

Threading and Tk don't mix well, as they violate the Tcl/Tk threading model of using Tk just from one thread and your code doesnt work, because you occupied the main (one and only) thread!

While your print-functions keeps printing - GUI is unresponsible because of that and you can check it easily with another print in your code:

>>> print('**** Active threads: %d ****' % threading.active_count())
**** Active threads: 1 ****

So what you really need is just create another one!

try:
    import tkinter as tk
    from tkinter import messagebox as msgbox
except ImportError:
    import Tkinter as tk
    import TkMessageBox as msgbox

import threading


def setInterval(func,time,args):
    e = threading.Event()
    while not e.wait(time):
        print('**** Active threads: %d ****' % threading.active_count())
        func(args)


def foo(data):
    print(data)
    aa("what")


def aa(a):
    print(a)


root = tk.Tk()

print('**** Active threads: %d ****' % threading.active_count())
thread = threading.Thread(target=setInterval, args=(foo, 5, "fsrty"))
msgbox.showinfo("Regret", "nope")
thread.start()

root.mainloop()

But here's another problem - threads keep running even after your close GUI (when you escaped mainloop)! So if you trying to achieve something simple - .after() is an option (quick and small alternative).

But if you stubborny or really need this - create (override) a custom subclass of the thread object, it's gives you more flexibility to control your flow!

try:
    import tkinter as tk
    from tkinter import messagebox as msgbox
except ImportError:
    import Tkinter as tk
    import TkMessageBox as msgbox

import threading


class Thread(threading.Thread):
    def __init__(self):
        super(Thread, self).__init__()
        self.running = False
        self.function_to_execute = None
        self._stop = threading.Event()

    def start_thread(self, func, *args, **kwargs):
        self.function_to_execute = (func, args, kwargs)
        self.running = True
        self.start()

    def run(self):
        print('### STARTED ###')
        while self.running:
            try:
                print('### RUNNING ###')
                function, args, kwargs = self.function_to_execute
                function(*args, **kwargs)
            except:
                self.stop()

    def stop(self):
        print('### STOPPING ###')
        self.running = False
        self._stop.set()


def setInterval(func, time, args):
    e = threading.Event()

    e.wait(time)
    print('**** Active threads: %d ****' % threading.active_count())
    func(args)


def foo(data):
    print(data)
    aa('what')


def aa(a):
    print(a)


def clear():
    thread.stop()

    while True:
        try:
            thread.is_alive()
        except TypeError:
            root.destroy()
            print('### STOPPED ###')
            print('**** Active threads: %d ****' % threading.active_count())
            break


root = tk.Tk()

thread = Thread()
print('**** Active threads: %d ****' % threading.active_count())
msgbox.showinfo("Regret", "nope")
thread.start_thread(setInterval, foo, 5, 'fsrty')
root.protocol('WM_DELETE_WINDOW', clear)

root.mainloop()

As you see - things are getting more complicated when we trying to clear out before exiting, but it's works!

Conclusion:

  • For simple things - .after() is a good option!
  • For complicated and long-executed things - threading is your choise!

Links:

Community
  • 1
  • 1
CommonSense
  • 4,232
  • 2
  • 14
  • 38