¿Por qué al instanciar la clase Calculadora
y pasarle como argumento root = tk.Tk
crea la ventana?
La ventana se crea porque instancias tk.Tk
, clase base para cualquier aplicación de Tkinter y que inicia el intérprete TCL y el ciclo de eventos. Es decir, lo que inicia la ventana es tk.Tk()
. Luego, para que el Frame
de tu clase Calculadora
pueda dibujarse en la ventana principal debes pasarle una instancia de esta ventana principal o una instancia de otro widget que ya pertenezca a esta ventana si fuera un widget anidado. Es exactamente lo mismo que cuando haces tk.Button(parent, text=...)
por ejemplo.
App.mainloop()
es el método de tk.Tk
encargado de iniciar el ciclo de eventos y por tanto de mostrar la ventana. Dicho método lo hereda Calculadora
de tk.Frame
que en esencia llama al método mainloop
de la ventana principal.
Realmente no es imprescindible pasar una instancia de tk.Tk
, si no lo haces implícitamente se genera una instancia de la misma a la que puedes acceder desde la instancia del Frame
mediante el atributo master
:
import tkinter as tk
class Calculadora(tk.Frame):
def __init__(self,root = None):
super().__init__(root)
self.master.title("Calculadora")
if __name__ == "__main__":
app = Calculadora()
app.mainloop()
¿Por qué la clase Calculadora
debe heredar de tk.Frame
?
No tendría por qué heredar de tk.Frame
, podría heredar de tk.Toplevel
, tk.Button
, tk.Canvas
, etc. O no heredar de nada y en vez de herencia usar composición, todo depende de cómo queramos estructurar la app.
import tkinter as tk
class Calculadora:
def __init__(self, root):
self.root = root
self.root.geometry("100x100")
self.master_frame = tk.Frame(root)
self.master_frame.pack(fill=tk.BOTH, expand=True)
self.root.title("Calculadora")
btn = tk.Button(self.master_frame, text="Hola")
btn.pack()
if __name__ == "__main__":
root = tk.Tk()
app = Calculadora(root)
root.mainloop()
tk.Frame
es un widget básico, representa simplemente una región rectangular en la pantalla con solo un puñado de características o atributos básicos (color de fondo, margenes, padding, bordes, etc). Esto lo hace muy útil como widget base para cualquier otro widget que queramos implementar o como contenedor de otros widgets. Esta es la raźón por la que se suele heredar de tk.Frame
, tu clase Calculadora
al heredar de tk.Frame
se convierte en un widget de Tkinter herendando con ello sus atributos y métodos, entre ellos pack
, grid
y place
por ejemplo.
¿Por qué al usar el método super()
tengo que llamar a root
si este es parte del constructor de la clase Calculadora
? , no se supone que super()
es para heredar los atributos y demás de la clase padre?
En super().__init__(root)
no llamas a root
, lo que haces es pasar al método __init__
de la clase padre (tk.Frame
) la instancia de la ventana principal para que tu clase pueda ser inicializada de forma correcta (y que entre otras cosas no cree una instancia tk.Tk
implícita como hemos visto).
Al tener Calculadora
un método __init__
definido se sobrescribe el heredado de tk.Frame
. Si no llamas al método __init__
del padre todas las tareas esenciales de inicialización que se llevan a cabo en él no tendrán lugar y simplemente tu clase Calculadora
será inútil porque no va a ser algo que se comporte como un widget de tkinter.
Para más información de que es y que hace super
ver: