有没有办法重新打开我已关闭的登录窗口?



我正在尝试创建一个套接字聊天,它正在为我工作。我的问题是,我正试图实现一个选项登出,回来与登录窗口,这是在栏菜单。我已经尝试了几种方法来重新打开这个窗口。

代码是西班牙语。但我认为这是可以理解的

这是客户端的代码:

from socket import *
from threading import *
from tkinter import *
from tkinter import messagebox
from tkinter import scrolledtext as scroll
from pymysql import Error
from pymysql import IntegrityError
import pymysql as sql
import conexion
class VentanaLogin:
def __init__(self, ventana):
self.ventana = ventana
self.ventana.title('Iniciar sesión')
self.database = conexion.Database()

# --- Frame Login ---
loginFrame = Frame(self.ventana, bg='grey8')
loginFrame.pack(side='top', fill=BOTH, expand=YES)
# --- Centrando ventana ---
width = 400
height = 480
anchoPantalla = self.ventana.winfo_screenwidth()
largoPantalla = self.ventana.winfo_screenheight()
coordenada_x = (anchoPantalla/2) - (width/2)
coordenada_y = (largoPantalla/2) - (height/2)
self.ventana.geometry(f'{width}x{height}+{int(coordenada_x)}+{int(coordenada_y)}')
# --- Entrada y boton de login ---
tituloLabel = Label(loginFrame, text='Programa de chat online', font=('Arial', 20), bg='grey8', fg='white', bd=0)
tituloLabel.pack(pady=50)
contraseñaLabel = Label(loginFrame, text='Ingrese su nombre de usuario', font=('Arial', 13), bg='grey13', fg='white', bd=0)
contraseñaLabel.pack()
self.usuarioEntry = Entry(loginFrame, font=('Arial', 13), width=25, bd=0)
self.usuarioEntry.pack(pady=(5,10))
self.usuarioEntry.focus()
contraseñaLabel = Label(loginFrame, text='Ingrese su contraseña', font=('Arial', 13), bg='grey13', fg='white', bd=0)
contraseñaLabel.pack()
self.contraseñaEntry = Entry(loginFrame, font=('Arial', 13), width=25, bd=0, show='*')
self.contraseñaEntry.pack(pady=(5,10))
loginBoton = Button(loginFrame, text='Iniciar sesión', bg='white', fg='black', font=('Arial', 14), width=15, bd=0, command=lambda:self.login(self))
loginBoton.pack(pady=(10,0))
registerLabel = Label(loginFrame, text='¿No tienes una cuenta?', bg='grey13', fg='white', font=('Arial', 10), bd=0)
registerLabel.pack(pady=(30,10))
registerBoton = Button(loginFrame, text='Registrarse', bg='white', fg='black', font=('Arial', 14), width=15, bd=0, command=lambda:self.registro(self))
registerBoton.pack()
# --- Tecla inicion de sesión ---
self.usuarioEntry.bind('<Return>', self.login)
self.contraseñaEntry.bind('<Return>', self.login)
def login(self, event):
usuario = self.usuarioEntry.get()
contraseña = self.contraseñaEntry.get()
parametros = (usuario, contraseña)
query = 'SELECT * FROM USUARIOS WHERE nombre = %s AND contraseña = %s'
peticion = self.database.consulta(query, parametros)
usuarioLogin = ''
contraseñaLogin = ''
for i in peticion:
usuarioLogin = i[1]
contraseñaLogin = i[2]

if usuario == usuarioLogin and contraseña == contraseñaLogin:
if usuario != '' or contraseña != '':
messagebox.showinfo('Iniciar sesión', 'Ha ingresado con éxito')
tk = Tk()
ventanaMain = VentanaMain(tk, usuario)
self.ventana.withdraw()
tk.mainloop()
else:
messagebox.showerror('Iniciar sesión', 'Ingrese los campos requeridos')
else:
messagebox.showerror('Iniciar sesión', 'Usuario o contraseña incorrectos')

def registro(self, event):
tk = Tk()
ventanaRegistro = VentanaRegistro(tk)
class VentanaRegistro:
def __init__(self, ventana):
self.ventana = ventana
self.ventana.title('Registro')
self.ventana.resizable(0,0)
self.database = conexion.Database()
# --- Centrando ventana ---
width = 400
height = 450
anchoPantalla = self.ventana.winfo_screenwidth()
largoPantalla = self.ventana.winfo_screenheight()
coordenada_x = (anchoPantalla/2) - (width/2)
coordenada_y = (largoPantalla/2) - (height/2)
self.ventana.geometry(f'{width}x{height}+{int(coordenada_x)}+{int(coordenada_y)}')
# --- Frame register ---
datosFrame = Frame(self.ventana, bg='grey8')
datosFrame.pack(side='top', fill=BOTH, expand=YES)

# --- Entrada y boton de registro ---
tituloLabel = Label(datosFrame, text='Registro de usuario', font=('Arial', 20), bg='grey8', fg='white')
tituloLabel.pack(pady=30)
nombreLabel = Label(datosFrame, text='Ingrese su nombre',font=('Arial', 13), bg='grey8', fg='white')
nombreLabel.pack()
self.nombreEntry = Entry(datosFrame, font=('Arial', 13), width=25, bd=0)
self.nombreEntry.pack(pady=(5,10))
self.nombreEntry.focus()
contraseñaLabel = Label(datosFrame, text='Ingrese su contraseña',font=('Arial', 13), bg='grey8', fg='white')
contraseñaLabel.pack()
self.contraseñaEntry = Entry(datosFrame, font=('Arial', 13), width=25, bd=0, show='*')
self.contraseñaEntry.pack(pady=(5,10))
correoLabel = Label(datosFrame, text='Ingrese su correo electrónico',font=('Arial', 13), bg='grey8', fg='white')
correoLabel.pack()
self.correoEntry = Entry(datosFrame, font=('Arial', 13), width=25, bd=0)
self.correoEntry.pack(pady=(5,10))
registroBoton = Button(datosFrame, text='Confirmar registro', bg='white', font=('Arial', 14), width=15, bd=0, command=lambda:self.registarUsuario(self))
registroBoton.pack(pady=5)
# --- Teclas para registro ---
self.nombreEntry.bind('<Return>', self.registarUsuario)
self.contraseñaEntry.bind('<Return>', self.registarUsuario)
self.correoEntry.bind('<Return>', self.registarUsuario)
def registarUsuario(self, event):
try:
usuario = self.nombreEntry.get()
contraseña = self.contraseñaEntry.get()
correo = self.correoEntry.get()
# --- Todos los campos deben estar completados ---
if usuario == '' or contraseña == '' or correo == '':
messagebox.showerror('Registro', 'Ingrese los campos requeridos')
else:
# --- Query INSERT --- 
parametros = (usuario, contraseña, correo)
query = 'INSERT INTO USUARIOS (nombre, contraseña, correo) VALUES (%s, %s, %s)'
self.database.consulta(query, parametros)
messagebox.showinfo('Registro', 'Usuario registrado exitosamente')
self.ventana.destroy()
except IntegrityError:
messagebox.showerror('Registro', 'Ya existe una cuenta con este nombre.')

class VentanaMain:
def __init__(self, ventana, usuario):
self.ventana = ventana
self.usuario = usuario
self.ventana.title('Chat')
self.ventana.resizable(0,0)
# --- Frame main ---
self.mainFrame = Frame(self.ventana, bg='grey8')
self.mainFrame.pack(side='top', fill=BOTH, expand=YES)
# --- Centrando ventana ---
width = 400
height = 550
anchoPantalla = self.ventana.winfo_screenwidth()
largoPantalla = self.ventana.winfo_screenheight()
coordenada_x = (anchoPantalla/2) - (width/2)
coordenada_y = (largoPantalla/2) - (height/2)
self.ventana.geometry(f'{width}x{height}+{int(coordenada_x)}+{int(coordenada_y)}')
# --- Texto del chat ---
self.texto = scroll.ScrolledText(self.mainFrame)
self.texto.pack(padx=20, pady=(20, 10))
self.textoLabel = Label(self.mainFrame, text='Escribir mensaje', font=('Arial', 12), bg='grey8', fg='white')
self.textoLabel.pack()
self.textoEntry = Entry(self.mainFrame, font=('Arial', 12), bd=0, width=30)
self.textoEntry.pack(pady=5)
self.textoEntry.focus()
self.textoButton = Button(self.mainFrame, text='Enviar', font=('Arial', 12), bg='white', fg='grey8', bd=0, width=20, command=lambda:self.enviarMensaje(self))
self.textoButton.pack(pady=5)
# --- Menus ---
self.menu = Menu(self.mainFrame)
self.ventana.config(menu=self.menu)
self.sesionMenu = Menu(self.menu, tearoff=0)
self.menu.add_cascade(label='Sesión', menu=self.sesionMenu)
self.sesionMenu.add_command(label='Cerrar sesión', command=self.cerrarSesión)
self.archivoMenu = Menu(self.menu, tearoff=0)
self.menu.add_cascade(label='Archivo', menu=self.archivoMenu)
self.sesionMenu.add_command(label='Salir', command=self.salirPrograma)

self.textoEntry.bind('<Return>', self.enviarMensaje)
try:
# --- Conexión servidor ---
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.connect(('127.0.0.1', 5050))
# --- Threads ---
self.hiloRecibir = Thread(target=self.recibirMensaje)
self.hiloRecibir.start()
except ConnectionRefusedError:
messagebox.showerror('Conexión', 'El servidor no se encuentra activo actualmente. Intente en otro momento')
self.ventana.destroy()
self.ventana.protocol('WM_DELETEN_WINDOW', self.procesoFinalizado)
def enviarMensaje(self, event):
mensaje = f'{self.usuario}: {self.textoEntry.get()}'
self.socket.send(mensaje.encode('utf-8'))
self.textoEntry.delete(0, END)
self.texto.insert(INSERT, mensaje + 'n')

def recibirMensaje(self):
self.texto.config(state='normal')
while True:
try:
mensaje = self.socket.recv(1024).decode('utf-8')
if mensaje == '@username':
self.socket.send(self.usuario.encode('utf-8'))
elif mensaje == '@otroDispositivo':
messagebox.showerror('Conexión', 'Ya has iniciado sesión al servidor')
self.ventana.destroy()
self.hiloRecibir.join()
elif mensaje == '@error':
messagebox.showerror('Conexión', 'El servidor ha sido desconectado')
self.ventana.destroy()
self.hiloRecibir.join()
else:
self.texto.insert(INSERT, mensaje + 'n')
except:
break
def cerrarSesión(self):    
# --- Here i'm trying to resolve this problem ---
tk = Tk()
ventanaLogin = VentanaLogin(tk)
self.salirPrograma()

def salirPrograma(self):
self.socket.send('@desconexion'.encode('utf-8'))
self.ventana.destroy()
self.hiloRecibir.join()
tk = Tk()
ventanaLogin = VentanaLogin(tk)
tk.mainloop()

我已经有一个方法来退出程序,按下"退出"菜单。对于"注销"菜单中我创建了方法" cerrarsession ",打开登录窗口并关闭主窗口,但它只是关闭,什么也没有出现。

我刚刚为一个朋友写了这个小例子,他问我如何在tkinter中显示登录窗口。

I came up with this

start.py

from gui import GUI
if __name__ == '__main__':
GUI()

gui.py

import sys
import tkinter
import security
from security import Security

def _check_user(user: str, password: str) -> bool:
if user == 'test' and password == 'test':
return True
return False

class GUI:
def __init__(self):
self.root = tkinter.Tk()
self.root.minsize(600, 300)
self._create_main_window()
self._show_login_window()
self.root.mainloop()
def authorize(self, user, password):
if _check_user(user, password):
self._show_main_window()
else:
security.show_alert_bad_login()
def on_closing(self):
self.root.destroy()
sys.exit(0)
def _show_main_window(self):
self.login_window.destroy()
self.root.deiconify()
def _show_login_window(self):
self.root.wm_withdraw()
self.login_window = tkinter.Toplevel(self.root)
self.login = Security(self, self.login_window)
def _create_main_window(self):
tkinter.Label(text='I am the main window').pack()
tkinter.Button(text='Show login window', command=self._show_login_window).pack()

security.py

import tkinter
from tkinter import messagebox

def show_alert_bad_login():
tkinter.messagebox.showerror(title='Wrong username or password',
message='Please check your username and password')

class Security(tkinter.Frame):
def __init__(self, maingui, window: tkinter.Toplevel):
super().__init__()
self.maingui = maingui
self.window = window
self.window.title("Login")
self.window.minsize(600, 300)
self.user = tkinter.StringVar(self.window)
self.password = tkinter.StringVar(self.window)
self.window.protocol("WM_DELETE_WINDOW", self.maingui.on_closing)
self._create_window()
def _create_window(self):
user_frame = tkinter.Frame(self.window)
user_frame.pack()
tkinter.Label(user_frame, text='User').pack(side=tkinter.LEFT)
tkinter.Entry(user_frame, textvariable=self.user).pack(side=tkinter.LEFT)
password_frame = tkinter.Frame(self.window)
password_frame.pack()
tkinter.Label(password_frame, text='Password').pack(side=tkinter.LEFT)
tkinter.Entry(password_frame, textvariable=self.password, show='*').pack(side=tkinter.LEFT)
tkinter.Button(self.window, text='login', command=self._authorize).pack()
def _authorize(self):
self.maingui.authorize(self.user.get(), self.password.get())

基本思想是在本例中定义主窗口(而不是登录窗口)self._create_main_window()

在显示登录窗口的地方,在本例中self._show_login_window(),主窗口被隐藏,登录窗口显示为TopWindow。

之后,如果你再次需要登录窗口,你可以调用self._show_login_window()函数,主窗口再次隐藏以显示登录窗口。

我没有对此进行广泛的测试,但它可能有助于理解这个想法。

最新更新