¿Qué hace llamar a Tk () en realidad?

Estaba trabajando con Tkinter cuando vi un ejemplo mínimo de la Referencia NMT Tkinter 8.5 .

#!/usr/bin/env python import tkinter as tk class Application(tk.Frame): def __init__(self, master=None): tk.Frame.__init__(self, master) self.grid() self.createWidgets() def createWidgets(self): self.quitButton = tk.Button(self, text='Quit',command=self.quit) self.quitButton.grid() app = Application() app.master.title('Sample application') app.mainloop() 

Está todo bien, hasta que me doy cuenta de que la clase Tk no se está inicializando. En otro material de referencia en línea que pude encontrar ( Python‘s Library Reference , effbot.org , TkDocs ), suele haber una llamada a root = tk.Tk() , a partir de la cual se basan el rest de los ejemplos. Tampoco vi ningún tipo de referencia a la inicialización de la clase Tk en ninguna parte de la referencia del NMT.

La información que podría obtener con respecto a la clase Tk también es vaga, ya que la Referencia de Python solo la muestra como un “widget de alto nivel … que generalmente es la ventana principal de una aplicación”. Por último, si sustituyo las últimas líneas en el fragmento que presenté anteriormente:

 root = tk.Tk() app = Application(root) 

El progtwig se ejecutaría tan bien como antes. Con todo esto en mente, lo que me interesa saber es:

  • ¿Qué hace en realidad el hecho de llamar a root = tk.Tk() (como en, qué se inicializa) y por qué puede funcionar el fragmento anterior sin él?
  • ¿Me encontraría con dificultades o limitaciones si no llamo a Tk() y simplemente construyo mi aplicación en torno a la clase Frame ?

Tkinter funciona iniciando un intérprete tcl / tk bajo las carátulas y luego traduciendo los comandos tkinter en comandos tcl / tk. La ventana principal y este intérprete están intrínsecamente vinculados, y ambos son necesarios para que funcione una aplicación tkinter.

La creación de una instancia de Tk inicializa este intérprete y crea la ventana raíz. Si no lo inicializa explícitamente, uno se creará implícitamente cuando cree su primer widget.

No creo que haya ninguna trampa al no inicializarlo usted mismo, pero como indica el zen de python, “explícito es mejor que implícito”. Su código será un poco más fácil de entender si crea explícitamente la instancia de Tk . Por ejemplo, evitará que otras personas hagan la misma pregunta sobre su código que usted acaba de preguntar sobre este otro código.

La respuesta de Bryan Oakley es acertada. La creación de un widget creará implícitamente una instancia del intérprete tcl / tk. Sin embargo, me gustaría agregar algunos fragmentos de código para comprender mejor cómo se crea implícitamente Tk.

Cuando se crea un objeto Widget (ya sea un Marco o un Botón o incluso un widget basado en ttk), se llama al método BaseWidget clase __init__ , que a su vez llama al método _setup . Aquí hay un fragmento de la parte relevante:

 def _setup(self, master, cnf): """Internal function. Sets up information about children.""" if _support_default_root: global _default_root if not master: if not _default_root: _default_root = Tk() master = _default_root self.master = master self.tk = master.tk 

Tanto _support_default_root como _default_root son variables globales, declaradas en las líneas 132-133 del archivo __init__.py en el paquete tkinter . Se inicializan a los siguientes valores:

 _support_default_root = 1 _default_root = None 

Esto significa que, si no se proporciona el master y si no se creó un intérprete, se crea una instancia de Tk y se asigna como la raíz predeterminada para todos los widgets futuros.

También hay algo interesante al crear una instancia de la clase Tk . El siguiente fragmento de Tk._loadtk proviene del método Tk._loadtk :

 if _support_default_root and not _default_root: _default_root = self 

Lo que significa que, independientemente de cómo se inicialice la clase Tk , siempre se configura como la raíz predeterminada.

A veces algunos widgets ejecutan Tk() por su cuenta. Pero no sé qué widgets y por qué.

A veces se ejecuta incluso si no usa mainloop() , principalmente en Windows.

Tkinter es un contenedor extraño en Tcl / Tk 🙂

Pero prefiero usar root = Tk() y root.mainloop() siempre.