Módulo usuarios

El módulo de usuario mas que nada es un CRUD ya que se pretende crear un ejecutable con la base de datos embebida de sqlite y entonces cuando se le instale la aplicación al cliente se prentende darle la aplicación con un registro de acesso por default y posteriormente el modulo usuario lo pueda cambiar. Esta es la segunda parte o la versión de código con el modelo agregargado de usuarios.
El archivo login.py quedaría de la siguiente forma:
 
  
    
import sqlite3
import tkinter as tk
from tkinter import messagebox, Entry
from tkinter import ttk



def bloquear_cierre():
    pass

def verificar_credenciales():
    email = entry_usuario.get()
    contra = entry_contrasena.get()
    conexion = sqlite3.connect('miconoprac.db')
    cursor = conexion.cursor()
    cursor.execute('SELECT * FROM usuario WHERE email = ? AND password = ?', (email,contra))

    usuario_valido = cursor.fetchone()

    conexion.close()



    if  usuario_valido:
        if email == usuario_valido[3] and contra == usuario_valido[4]:
            messagebox.showinfo("Éxito", "¡Inicio de sesión exitoso!")
            ventana.withdraw()
            abrir_ventana_principal()

    else:
        messagebox.showerror("Error", "Usuario o contraseña incorrectos")


def abrir_ventana_principal():
    # Creamos la nueva ventana
    ventana_principal = tk.Toplevel()
    ventana_principal.title("Mi Control de nómina práctico")
    ventana_principal.geometry("400x300")
    barra_menus = tk.Menu()
    menu_usuario = tk.Menu(barra_menus, tearoff=False)
    menu_nomina = tk.Menu(barra_menus, tearoff=False)
    menu_salir = tk.Menu(barra_menus, tearoff=False)
    barra_menus.add_cascade(menu=menu_usuario, label="Usuarios")
    barra_menus.add_cascade(menu=menu_nomina, label="Nómina")
    barra_menus.add_cascade(menu=menu_salir, label="Salir")
    menu_usuario.add_command(label="Registrar Usuarios", command=ventana_usuarios)
    menu_salir.add_command(label="Salir", command=ventana.destroy)
    # Elementos de la nueva ventana
    tk.Label(ventana_principal, text="MICONOPRAC", font=("Arial", 18)).pack(pady=50)
    ventana_principal.protocol("WM_DELETE_WINDOW", bloquear_cierre)
    ventana_principal.config(menu=barra_menus)

def ventana_usuarios():
    abrir_ventana_usuarios()

def abrir_ventana_usuarios():
    ventana_usuario = tk.Toplevel()
    ventana_usuario.title("Panel Usuarios")
    ventana_usuario.geometry("800x670")
    tk.Label(ventana_usuario, text="Registro de usuarios", fg="black",font=("Comic Sans", 17, "bold"), pady=10).pack()
    marco = tk.LabelFrame(ventana_usuario, text="Información de Usuarios", font=("Comic Sans", 10, "bold"), pady=5)
    marco.config(bd=2)
    marco.pack()
    tk.Label(marco, text="Nombre: ", font=("Comic Sans", 10, "bold")).grid(row=0, column=0,pady=8)
    nombre=tk.Entry(marco,width=25)
    nombre.focus()
    nombre.grid(row=0, column=1, padx=5, pady=8)
    tk.Label(marco, text="Apellido Paterno: ", font=("Comic Sans", 10, "bold")).grid(row=1, column=0, pady=8)
    apellido_paterno = tk.Entry(marco, width=25)
    apellido_paterno.grid(row=1, column=1, padx=5, pady=8)
    tk.Label(marco, text="Apellido Materno: ", font=("Comic Sans", 10, "bold")).grid(row=2, column=0, pady=8)
    apellido_materno = tk.Entry(marco, width=25)
    apellido_materno.grid(row=2, column=1, padx=5, pady=8)
    tk.Label(marco, text="Email: ", font=("Comic Sans", 10, "bold")).grid(row=0, column=2, pady=8)
    email = tk.Entry(marco, width=40)
    email.grid(row=0, column=3, padx=5, pady=8)
    tk.Label(marco, text="Password: ", font=("Comic Sans", 10, "bold")).grid(row=1, column=2, pady=8)
    contra = tk.Entry(marco, width=25)
    contra.grid(row=1, column=3, padx=5, pady=8)
    frame_botones = tk.Frame(ventana_usuario)
    frame_botones.pack()
    tk.Button(frame_botones,command=lambda:[agregar_usuario(nombre.get() ,apellido_paterno.get() ,apellido_materno.get(),email.get(),contra.get(),tree),Limpiar_formulario(nombre,apellido_paterno,apellido_materno,email,contra)], text="REGISTRAR", height=2, width=10, bg="green", fg="white",font=("Comic Sans", 10, "bold")).grid(row=0, column=1, padx=10, pady=15)
    tk.Button(frame_botones,command=lambda:editarUsuario(tree),text="EDITAR", height=2, width=10, bg="gray", fg="white",font=("Comic Sans", 10, "bold")).grid(row=0, column=2, padx=10, pady=15)
    tk.Button(frame_botones,command=lambda:Eliminar_usuario(tree), text="ELIMINAR", height=2, width=10, bg="red", fg="white",font=("Comic Sans", 10, "bold")).grid(row=0, column=3, padx=10, pady=15)
    tree = ttk.Treeview(ventana_usuario, columns=("columna1", "columna2", "columna3", "columna4", "columna5"),show="headings")
    tree.heading("columna1", text='Nombre', anchor="center")
    tree.column("columna1", width=150)
    tree.heading("columna2", text='Apellido Paterno', anchor="center")
    tree.column("columna2", width=100)
    tree.heading("columna3", text='Apellido Materno', anchor="center")
    tree.column("columna3", width=100)
    tree.heading("columna4", text='Email', anchor="center")
    tree.column("columna4", width=150)
    tree.heading("columna5", text='Password', anchor="center")
    tree.column("columna5", width=100)

    tree.pack()
    obtener_usuarios(tree)


def Ejecutar_consulta(query, parameters=()):
    with sqlite3.connect('miconoprac.db') as conexion:
        cursor = conexion.cursor()
        result = cursor.execute(query, parameters)
        conexion.commit()
        conexion.close()
        return result

def obtener_usuarios(tree):
    records = tree.get_children()
    for element in records:
        tree.delete(element)
    conexion = sqlite3.connect('miconoprac.db')
    cursor = conexion.cursor()
    cursor.execute('SELECT * FROM usuario ')
    usuarios = cursor.fetchall()
    for row in usuarios:
        tree.insert("","end", text="", values=(row[0], row[1], row[2], row[3], row[4]))
    conexion.close()

def Ejecutar_consulta(query, parameters=()):
        with sqlite3.connect('miconoprac.db') as conexion:
            cursor=conexion.cursor()
            result=cursor.execute(query,parameters)
            conexion.commit()
        return result

def agregar_usuario(nombre,apellido_paterno,apellido_materno,email,contra,tree):
    if Validar_formulario_completo(nombre,apellido_paterno, email, contra):
        query = 'INSERT INTO usuario VALUES( ?, ?, ?, ?, ?)'
        parameters = (nombre,apellido_paterno,apellido_materno,email,contra)
        Ejecutar_consulta(query, parameters)
        messagebox.showinfo("REGISTRO EXITOSO", f'Usuario registrado: {email}')
        obtener_usuarios(tree)

def Validar_formulario_completo(nombre,apellido_paterno,email,contra):
    if len(nombre) != 0 and len(apellido_paterno) != 0 and len(email) != 0 and len(contra) != 0:
        return True
    else:
        messagebox.showerror("ERROR", "Complete todos los campos del formulario")

def Limpiar_formulario(nombre,apellido_paterno,apellido_materno,email,contra):
    nombre.delete(0,'end')
    apellido_paterno.delete(0,'end')
    apellido_materno.delete(0,'end')
    email.delete(0,'end')
    contra.delete(0,'end')

def Eliminar_usuario(tree):

    seleccion=tree.selection()



    if seleccion:
        item_id = seleccion[0]
        info = tree.item(item_id, "values")
        #print("Valores seleccionados:", info)
        nombre = info[0]
        email = info[3]
        respuesta = messagebox.askquestion("ADVERTENCIA", f"¿Seguro que desea eliminar el usuario: {nombre}?")
        if respuesta == 'yes':
            query = "DELETE FROM usuario WHERE email = ?"
            parameters=(email,)
            Ejecutar_consulta(query,parameters)
            obtener_usuarios(tree)
            messagebox.showinfo('EXITO', f'Usario eliminado: {nombre}')
        else:
            messagebox.showerror('ERROR', f'Error al eliminar el usario: {nombre}')
    else:
        messagebox.showerror("ERROR", "Porfavor selecciona un elemento")


def editarUsuario(tree):
    seleccion = tree.selection()
    if seleccion:
        item_id = seleccion[0]
        info = tree.item(item_id, "values")
        nombre = info[0]
        apellido_paterno=info[1]
        apellido_materno=info[2]
        email=info[3]
        contra=info[4]
        modal = tk.Toplevel()
        modal.title("Editar Usuario")
        modal.geometry("700x500")

        # Hacer que la ventana sea modal
        modal.grab_set()
        tk.Label(modal, text="Registro de usuarios", fg="black", font=("Comic Sans", 17, "bold"),
                 pady=10).pack()
        marco = tk.LabelFrame(modal, text="Información de Usuarios", font=("Comic Sans", 10, "bold"), pady=5)
        marco.config(bd=2)
        marco.pack()
        tk.Label(marco, text="Nombre: ", font=("Comic Sans", 10, "bold")).grid(row=0, column=0, pady=8)
        nuevoNombre = tk.Entry(marco,textvariable=tk.StringVar(marco,value=nombre), width=25)
        nuevoNombre.focus()
        nuevoNombre.grid(row=0, column=1, padx=5, pady=8)
        tk.Label(marco, text="Apellido Paterno: ", font=("Comic Sans", 10, "bold")).grid(row=1, column=0, pady=8)
        nuevoApellido_paterno = tk.Entry(marco,textvariable=tk.StringVar(marco,value=apellido_paterno), width=25)
        nuevoApellido_paterno.grid(row=1, column=1, padx=5, pady=8)
        tk.Label(marco, text="Apellido Materno: ", font=("Comic Sans", 10, "bold")).grid(row=2, column=0, pady=8)
        nuevoApellido_materno = tk.Entry(marco,textvariable=tk.StringVar(marco,value=apellido_materno), width=25)
        nuevoApellido_materno.grid(row=2, column=1, padx=5, pady=8)
        tk.Label(marco, text="Email: ", font=("Comic Sans", 10, "bold")).grid(row=0, column=2, pady=8)
        nuevoEmail = tk.Entry(marco,textvariable=tk.StringVar(marco,value=email), width=40,state="readonly")
        nuevoEmail.grid(row=0, column=3, padx=5, pady=8)
        tk.Label(marco, text="Password: ", font=("Comic Sans", 10, "bold")).grid(row=1, column=2, pady=8)
        nuevoContra = tk.Entry(marco,textvariable=tk.StringVar(marco,value=contra), width=25)
        nuevoContra.grid(row=1, column=3, padx=5, pady=8)

        frame_botones = tk.Frame(modal)
        frame_botones.pack()
        tk.Button(frame_botones, command=modal.destroy,text="Cancelar", height=2, width=10, bg="green", fg="white", font=("Comic Sans", 10, "bold")).grid(row=0, column=1, padx=10, pady=15)
        tk.Button(frame_botones,command=lambda:Actualizar_usuario(nuevoNombre.get(),nuevoApellido_paterno.get(),nuevoApellido_materno.get(),nuevoEmail.get(),nuevoContra.get(),tree,modal), text="ACTUALIZAR USUARIO", height=2, width=30, bg="gray", fg="white",
                  font=("Comic Sans", 10, "bold")).grid(row=0, column=2, padx=10, pady=15)









    else:
        messagebox.showerror("ERROR", "Porfavor selecciona un elemento")



def Actualizar_usuario(nuevoNombre,nuevoApellido_paterno,nuevoApellido_materno,nuevoEmail,nuevoContra,tree,modal):
    if Validar_formulario_completo(nuevoNombre,nuevoApellido_paterno,nuevoEmail,nuevoContra):
        query='Update usuario SET nombre=?,apellido_paterno=?,apellido_materno=?,password=? WHERE email=?'
        parameters=(nuevoNombre,nuevoApellido_paterno,nuevoApellido_materno,nuevoContra,nuevoEmail)
        Ejecutar_consulta(query,parameters)
        messagebox.showinfo('EXITO', f'Usuario actualizado:{nuevoNombre}')
        modal.destroy()
        obtener_usuarios(tree)


        # Configuración de la ventana principal
ventana = tk.Tk()
ventana.title("Inicio de sesión")
ventana.geometry("400x500")
ventana.eval('tk::PlaceWindow . center') # Centra la ventana en la pantalla

# Etiquetas y campos de entrada
tk.Label(ventana, text="Email:").pack(pady=10)
entry_usuario = tk.Entry(ventana,width=30)
entry_usuario.pack()

tk.Label(ventana, text="Contraseña:").pack(pady=10)
entry_contrasena = tk.Entry(ventana, show="*",width=30) # El 'show' oculta los caracteres
entry_contrasena.pack()

# Botón de Login
tk.Button(ventana, text="Iniciar Sesión", command=verificar_credenciales).pack(pady=20)

# Bucle principal para mantener la ventana abierta
ventana.mainloop()	  

	  
	  
	  
    
   

Segunda prueba

Corremos el ejemplo para probar el módulo de usuario