Tkinter recursión involuntaria con el comando de la barra de menú … ¿porque?

Estoy tratando de hacer una GUI de Python usando tkinter , y necesito un elemento de menú que abra otra copia de la ventana principal. Intenté hacer el siguiente código, y cuando ejecuté el progtwig, se congeló un poco y luego abrí una gran cantidad de ventanas. El último mensaje de error impreso está abajo.

Tengo dos preguntas.

  1. ¿Cómo puedo realizar la tarea de hacer que el botón “Nuevo” abra una nueva ventana y una instancia de la clase TheThing ? (En IDLE, File > New File tiene el comportamiento que estoy buscando).
  2. ¿Por qué está ocurriendo este error?

     RecursionError: maximum recursion depth exceeded while calling a Python object 

Mi código:

 import tkinter as tk class TheThing: def __init__(self, root): root.option_add('*tearOff', False) menubar = tk.Menu(root) root.config(menu = menubar) file = tk.Menu(menubar) menubar.add_cascade(menu = file, label = "File") file.add_command(label = 'New', command = doathing()) def doathing(): thing1 = tk.Tk() thing2 = TheThing(thing1) def main(): win = tk.Tk() do = TheThing(win) win.mainloop() if __name__ == '__main__': main() 

Lugares en los que ya he buscado respuestas:

  • Esta pregunta parecía que estaba teniendo un problema muy similar. Tal vez pueda estudiar eso y encontrar una solución, pero aún no entiendo el problema.

  • Esta pregunta era sobre la recursión, python y tkinter, pero parecía ser más after eso.

El problema está en esta línea:

  file.add_command(label = 'New', command = doathing()) 

Aquí, ejecuta la doathing llamada doathing y luego intenta vincular su resultado (que es None ) al comando. En este caso específico, esto también conduce a una recursión infinita, ya que la callback creará una nueva instancia del marco, que ejecutará nuevamente la callback, que creará otro marco, y así sucesivamente. En lugar de llamar a la función, debe vincular la función al comando.

  file.add_command(label = 'New', command = doathing) # no () 

En caso de que necesite pasar parámetros a esa función (no es el caso aquí) puede usar un lambda :

  file.add_command(label = 'New', command = lambda: doathing(params)) 

Además, en lugar de crear otra instancia de Tk , probablemente debería crear una instancia de Toplevel en la callback, es decir,

 def doathing(): thing1 = tk.Toplevel() thing2 = TheThing(thing1)