Foro de elhacker.net

Programación => Scripting => Mensaje iniciado por: DeMoNcRaZy en 6 Agosto 2023, 02:14 am



Título: Error al cerrar ventana principal tkinter con destroy()
Publicado por: DeMoNcRaZy en 6 Agosto 2023, 02:14 am
Buenas, tengo un problema estoy intentado cerrar la ventana principal al hacel login, con destroy(), pero me lanza error ¿por qué? que estoy haciendo mal? como podria solucionarlo, cualquier informacion adicional lo agradeceria.
el error que me lanza cuando presiono el boton y quiero cerrar la ventana es el siguiente:

Código
  1. Exception in Tkinter callback
  2. Traceback (most recent call last):
  3.  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/tkinter/__init__.py", line 1948, in __call__
  4.    return self.func(*args)
  5.           ^^^^^^^^^^^^^^^^
  6.  File "/Users/tomassanchezgarcia/Desktop/python-test/iniciar_sesion.py", line 84, in validar
  7.    self.root.destroy()
  8.    ^^^^^^^^^
  9. AttributeError: 'Login' object has no attribute 'root'

main.py

Código
  1. from tkinter import *
  2. from tkinter import ttk
  3. import tkinter as tk
  4. import pymysql
  5. from conexion import *
  6. from tkinter import messagebox
  7. from PIL import Image, ImageTk
  8. from iniciar_sesion import Login
  9.  
  10. class AplicacionInventario:
  11.  
  12.    def __init__(self):
  13.        self.root = Tk()
  14.        self.root.title("StockMaster")
  15.        self.root.geometry("400x500")
  16.        #Bloquear agrandar ventana
  17.        self.root.resizable(0,0)
  18.  
  19.        self.wtotal = self.root.winfo_screenwidth()
  20.        self.htotal = self.root.winfo_screenheight()
  21.        #  Guardamos el largo y alto de la ventana
  22.        self.wventana = 400
  23.        self.hventana = 500
  24.        # #  Aplicamos la siguiente formula para calcular donde debería posicionarse
  25.        self.pwidth = round(self.wtotal/2-self.wventana/2)
  26.        self.pheight = round(self.htotal/2-self.hventana/2)
  27.        #  Se lo aplicamos a la geometría de la ventana
  28.        self.root.geometry(str(self.wventana)+"x"+str(self.hventana)+"+"+str(self.pwidth)+"+"+str(self.pheight))
  29.  
  30.        self.imagen = Image.open("src/logo.png")
  31.        self.imagen = self.imagen.resize((350, 100))  # Opcional: Redimensionar la imagen
  32.        self.imagen = ImageTk.PhotoImage(self.imagen)
  33.        # Crear un widget Label con la imagen y colocarlo en la ventana
  34.        self.label_imagen = tk.Label(self.root, image=self.imagen)
  35.        self.label_imagen.pack(pady=20)
  36.  
  37.        self.login1 = Login(self)
  38.  
  39.  
  40.        #fetch_data_button = tk.Button(self.root, text="Obtener Datos", command=self.mostrar2)
  41.        #fetch_data_button.pack()
  42.  
  43.  
  44.        self.root.mainloop()
  45.  
  46. AplicacionInventario()

iniciar_sesion.py

Código
  1. from tkinter import *
  2. from tkinter import ttk
  3. import tkinter as tk
  4. import pymysql
  5. from conexion import *
  6. from tkinter import messagebox
  7. from PIL import Image, ImageTk
  8. from test2 import Menus
  9.  
  10. class Login:
  11.    def __init__(self, app):
  12.        self.app = app
  13.  
  14.        self.t_Email = "Email:"
  15.        self.label_email = tk.Label(text=self.t_Email)
  16.        self.label_email.pack(pady=5, padx=20)
  17.        self.label_email.place(x=150, y=150, width=100, height=20)
  18.  
  19.        self.entry_email = tk.Entry()
  20.        self.entry_email.pack(pady=5)
  21.        self.entry_email.place(x=75, y=170, width=250, height=50)
  22.  
  23.        self.t_Password = "Contraseña:"
  24.        self.label_password = tk.Label(text=self.t_Password)
  25.        self.label_password.pack(pady=5, padx=20)
  26.        self.label_password.place(x=150, y=220, width=100, height=20)
  27.  
  28.        self.entry_password = tk.Entry(show="*")
  29.        self.entry_password.pack(pady=5)
  30.        self.entry_password.place(x=75, y=240, width=250, height=50)
  31.  
  32.        self.login_email = self.entry_email.get()
  33.        self.login_password = self.entry_password.get()
  34.  
  35.        self.boton_login = tk.Button(text="Iniciar Sesión", command=self.validar)
  36.        self.boton_login.pack(pady=5)
  37.        self.boton_login.place(x=125, y=300, width=150, height=50)
  38.  
  39.    def validar(self):
  40.        #self.conexion_login = connect_to_database()
  41.        #self.cursor_conexion_login = self.conexion_login.cursor()
  42.  
  43.        #self.cursor_conexion_login.execute("SELECT email, password FROM usuarios WHERE email=%s AND password=%s", (self.login_email, self.login_password))
  44.        #self.verificar_login = self.cursor_conexion_login.fetchall()
  45.  
  46.        #messagebox.showwarning("Advertencia", self.verificar_login)
  47.  
  48.        # Conectarse a la base de datos utilizando la función importada
  49.        self.connection2 = connect_to_database()
  50.        self.cursor2 = self.connection2.cursor()
  51.        # Ejemplo: Ejecutar una consulta para obtener datos
  52.        self.cursor2.execute("SELECT nombre,password FROM usuarios")
  53.        self.data2 = self.cursor2.fetchall()
  54.        #messagebox.showwarning("Advertencia", self.data2)
  55.        # Cerrar el cursor y la conexión
  56.        for self.fila in self.data2:
  57.            self.v_email = self.fila[0]
  58.            self.v_password = self.fila[1]
  59.  
  60.        self.cursor2.close()
  61.        self.connection2.close()
  62.        if self.entry_email.get() == "" or self.entry_password.get() == "":
  63.            self.dialogo = tk.Toplevel()
  64.            self.dialogo.title("Diálogo Personalizado")
  65.            self.dialogo.geometry("300x50")
  66.            self.dialogo.resizable(0,0)
  67.  
  68.            self.wtotal2 = self.dialogo.winfo_screenwidth()
  69.            self.htotal2 = self.dialogo.winfo_screenheight()
  70.  
  71.            self.wventana2 = 300
  72.            self.hventana2 = 50
  73.  
  74.            self.pwidth2 = round(self.wtotal2/2-self.wventana2/2)
  75.            self.pheight2 = round(self.htotal2/2-self.hventana2/2)
  76.  
  77.            self.dialogo.geometry(str(self.wventana2)+"x"+str(self.hventana2)+"+"+str(self.pwidth2)+"+"+str(self.pheight2))
  78.            self.etiqueta = tk.Label(self.dialogo, text="Este es un cuadro de diálogo personalizado.", padx=10, pady=10)
  79.            self.etiqueta.pack()
  80.        elif self.entry_email.get() == self.v_email and self.entry_password.get() == self.v_password:
  81.            #messagebox.showwarning("Advertencia", "PERFECTO COINCIDE")
  82.            self.ventana_menu = Menus(self)
  83.        else:
  84.            self.root.destroy()
  85.            messagebox.showwarning("Advertencia", "Los datos introducidos son incorrectos.")


Título: Re: Error al cerrar ventana principal tkinter con destroy()
Publicado por: Locura_23 en 13 Agosto 2023, 19:33 pm
Hola, un poco tarde pero si quieres utilizar el metodo .destroy() no tienes que hacer que la clase Login herede de tkinter.Tk ? para que herede ese método junto con todos los propios de un componente window.

Código
  1. import tkinter
  2.  
  3. class Login(tkinter.Tk):
  4.   def __init__(self):
  5.       #etc . . .

Otra cosa es que, en la línea 84, invocas a un atributo root de la clase Login ( que es lo que te tira error)
Código
  1. self.root.destroy()

Pero en ningún lugar de la clase Login definiste ese atributo, lo cual es lo que te dice el error. Yo supongo que root debería ser la ventana padre, o un componente window que contenga a Login. Tal vez lo quisiste pasar por el constructor, en la línea 12:

Código
  1. class Login:
  2.    def __init__(self, app):
  3.        self.app = app
  4.  

Pero luego no estas utilizando ese atributo, sino root, que la clase Login no conoce lo que es.