Nickpick
Nickpick

Reputation: 6597

Tkinter.self causing infinite loop with error

The following program gives an error message:

"RuntimeError: maximum recursion depth exceeded while calling a Python object".

The cause is the self.after.

It works fine when I create a while true loop in the Calculation function, but I would like to cause the loop with a self.after, which is how I read it should be done in connection with Tkinter. Any suggestions are appreciated.

import Tkinter as tk
import ttk
import time

class App(tk.Tk):
    def __init__(self):
        self.root=tk.Tk()
        self.var1=tk.StringVar()
        self.i=0

    def Calculation(self):
        # complex calculations that last 30 minutes in total
        self.i+=1
        self.var1.set(str(self.i))
        self.root.update()
        self.after(100, self.Calculation)

    def Gui(self):
        your_label=tk.Label(self.root,textvariable=self.var1).pack()

A=App()
A.Gui()
A.Calculation()

Upvotes: 1

Views: 493

Answers (2)

martineau
martineau

Reputation: 123501

The recursion is being caused by your App class being derived from tk.TK rather than tk.Frame. On top of that, your __init__() method creates a second instance of its own base class with the self.root=tk.Tk() statement instead of calling its base class's __init__() method as it should. This is especially troublesome in this case because an instance of the tk.TK class is the Toplevel widget of Tk which contains the Tcl interpreter and there generally should only ever be one of them in existence.

Here's something that changes the base class and accomplishes what I think you're trying to do in the proper manner. In it I've corrected, modified, and simplified a number other things, notably making the code conform to the PEP8 style guidelines.

import Tkinter as tk

class App(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack()
        self.var1 = tk.StringVar()
        self.i = 0
        tk.Label(self, textvariable=self.var1).pack()

    def calculation(self):
        # complex calculations that last 30 minutes in total
        self.i += 1
        self.var1.set(str(self.i))
#        self.update()  # no need, will be automatic as mainloop() runs
        self.after(100, self.calculation)

app=App()
app.calculation()  # start calculations
app.mainloop()  # run gui

Upvotes: 4

Dportology
Dportology

Reputation: 808

So I did a little bit of a rewrite by getting rid of the separate Gui function but I think this should do what you want it to do.

import Tkinter as tk
import ttk
import time

class App():
    def __init__(self):
        self.root = tk.Tk()
        self.i = 0
        self.label = tk.Label(text=str(self.i))
        self.label.pack()
        self.calculation()
        self.root.mainloop()

    def calculation(self):
        self.i = self.i + 1
        self.label.configure(text=self.i)
        self.root.after(100, self.calculation)

app=App()

Upvotes: 0

Related Questions