You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter GUI反复点击返回按钮后自动关闭问题排查

Tkinter GUI返回按钮二次点击导致程序无提示关闭问题

我的Python Tkinter GUI存在如下问题:点击左上角返回按钮可回到主界面,点击注册按钮进入注册界面操作正常,但再次点击返回按钮时,GUI会无提示自动关闭,终端未输出任何报错信息。

注册页面代码(含返回按钮)

import sqlite3
from tkinter import *
from tkinter import messagebox  # Import messagebox for error messages
import re  # Import re module for regular expressions
import customtkinter
from PIL import ImageTk, Image


# Destroy this window and open the login screen
def login():
    register_screen.destroy()
    import login  # Assuming there is a login.py file to open the login screen

def main():
    register_screen.destroy()
    import main


def register_user():
    # Get username and password
    username_value = username.get()
    password_value = password.get()
    
    # Check password requirements
    # Check if there is at least one capital letter in the password section
    if not re.search(r"[A-Z]", password_value):
        error_label.config(text="Password must contain at least one capital letter", fg="red")
        return
    # Check if there is at least one number in the password section
    if not re.search(r"\d", password_value):
        error_label.config(text="Password must contain at least one number", fg="red")
        return
    # Check if there is at least one symbol in the password section
    if not re.search(r"\W", password_value):
        error_label.config(text="Password must contain at least one symbol", fg="red")
        return
    
    # Insert the user into the database
    cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)", (username_value, password_value))
    connection.commit()
    
    login()


# Designing for registration
register_screen = tk.Tk()
register_screen.title("Register")
register_screen.geometry("500x800")
register_screen.resizable(width=False, height=False)

# Create a database connection
connection = sqlite3.connect("db/registration.db")
cursor = connection.cursor()

# Create a table for registration
cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, password TEXT)")

# Background image
background_image_login = PhotoImage(file="assets/background2.png")
background_label_login = Label(register_screen, image=background_image_login)
background_label_login.place(x=0, y=0, relwidth=1, relheight=1)

# Creating an empty tuple for username and password
username = StringVar()
password = StringVar()

# Create an empty label for the image
logo = ImageTk.PhotoImage(Image.open("assets/Logo.png").resize((180, 130), Image.ANTIALIAS))
logo1 = customtkinter.CTkButton(master=register_screen, image=logo, text="", compound="left", hover=False, bg_color="#020202")
logo1.place(relx=0.48, rely=0.2, anchor=CENTER)

# Create an empty label for the text
username_label = Label(register_screen, text="Username")
username_label.place(relx=0.5, rely=0.3, anchor=CENTER)

# Create a customentry widget for username
username_entry = customtkinter.CTkEntry(master=register_screen, textvariable=username, placeholder_text="Username", height=35, width=250)
username_entry.place(relx=0.5, rely=0.35, anchor=CENTER)

# Create an empty label for the text
password_label = Label(register_screen, text="Password")
password_label.place(relx=0.5, rely=0.4, anchor=CENTER)

# Create a customentry widget for password
password_entry = customtkinter.CTkEntry(master=register_screen, textvariable=password, placeholder_text="Password", height=35, width=250, show="*")
password_entry.place(relx=0.5, rely=0.45, anchor=CENTER)

# Create a button
register_button = customtkinter.CTkButton(master=register_screen, text="Register", command=register_user, height=35, width=250)
register_button.place(relx=0.5, rely=0.55, anchor=CENTER)

# Create an empty label for the error message
error_label = Label(register_screen, text="", fg="red")
error_label.place(relx=0.5, rely=0.62, anchor=CENTER)

arrow_image = ImageTk.PhotoImage(Image.open("assets/hi.png").resize((50, 50), Image.ANTIALIAS))
arrow_button = customtkinter.CTkButton(master= register_screen,image = arrow_image,text="", compound="left" ,fg_color='black', hover_color='black', command= main) 
arrow_button.place(relx=0.1 , rely = 0.1, anchor = CENTER)


register_screen.mainloop()

# Close the database connection
connection.close() 

主页面代码

import tkinter
from tkinter import *
import os
import customtkinter
from PIL import ImageTk, Image

root = Tk()
# Designing the main screen
def main_screen():
    root.geometry("500x800")
    main_frame = Frame(root,bg ='#020202')
    main_frame.pack(padx=20)
    main_frame.pack()
    background_image = PhotoImage(file="assets/Aim high.png")
    background_label = Label(root,image = background_image)
    background_label.place(x=0, y=0, relwidth = 1 , relheight = 1)
    root.title("Account Login")
    top_text=Label(root,text="Welcome to FitQuest",bg="#020202",font=("Calibri", 45))
    top_text.pack(pady=0, anchor =tkinter.CENTER)
    
    def register():
        root.destroy()
        import register
    
    def login():
        root.destroy()
        import login
    
    #Login button 
    Login_button = customtkinter.CTkButton(master=root, text="Login", command=login, height = 35, width = 250,bg_color="#020202")
    Login_button.place(relx=0.48, rely=0.3, anchor=tkinter.CENTER)
    #register button
    register_button = customtkinter.CTkButton(master=root, text="Register", command=register,height = 35, width = 250, bg_color="#020202" )
    register_button.place(relx=0.48, rely=0.4, anchor=tkinter.CENTER)
    #Logo act as a button 
    logo = ImageTk.PhotoImage(Image.open("assets/Logo.png"),Image.ANTIALIAS)
    button1 =customtkinter.CTkButton(master=root,image=logo,text="",compound="left" , hover=False, bg_color="#020202")
    button1.place(relx=0.48, rely=0.158, anchor=tkinter.CENTER)
    
 
    root.mainloop()
main_screen() 

问题原因与修复方案

核心问题

  1. 模块重复导入冲突:每次切换页面时直接import目标模块,会重复执行模块内的全局代码。主页面中root = Tk()是全局变量,第二次导入时会创建新的Tk实例,引发窗口逻辑混乱,导致程序退出。
  2. 窗口管理逻辑错误:直接销毁当前窗口后依赖模块导入自动创建新窗口,这种方式不可控,容易因模块重复加载产生异常。

修复步骤

1. 重构主页面代码(main.py)

import tkinter
from tkinter import *
import customtkinter
from PIL import ImageTk, Image

def main_screen():
    # 每次调用创建新窗口,避免全局变量冲突
    root = Tk()
    root.geometry("500x800")
    root.title("Account Login")
    
    main_frame = Frame(root, bg='#020202')
    main_frame.pack(padx=20)
    
    background_image = PhotoImage(file="assets/Aim high.png")
    background_label = Label(root, image=background_image)
    background_label.place(x=0, y=0, relwidth=1, relheight=1)
    
    top_text = Label(root, text="Welcome to FitQuest", bg="#020202", font=("Calibri", 45))
    top_text.pack(pady=0, anchor=tkinter.CENTER)
    
    def register():
        root.destroy()
        # 导入后调用注册页面入口函数
        import register
        register.show_register_screen()
    
    def login():
        root.destroy()
        import login
        login.show_login_screen()
    
    # 登录按钮
    Login_button = customtkinter.CTkButton(master=root, text="Login", command=login, height=35, width=250, bg_color="#020202")
    Login_button.place(relx=0.48, rely=0.3, anchor=tkinter.CENTER)
    
    # 注册按钮
    register_button = customtkinter.CTkButton(master=root, text="Register", command=register, height=35, width=250, bg_color="#020202")
    register_button.place(relx=0.48, rely=0.4, anchor=tkinter.CENTER)
    
    # Logo按钮
    logo = ImageTk.PhotoImage(Image.open("assets/Logo.png"), Image.ANTIALIAS)
    button1 = customtkinter.CTkButton(master=root, image=logo, text="", compound="left", hover=False, bg_color="#020202")
    button1.place(relx=0.48, rely=0.158, anchor=tkinter.CENTER)
    
    # 绑定图片到窗口,防止被垃圾回收
    root.background_image = background_image
    root.logo = logo
    
    root.mainloop()

# 仅直接运行模块时启动主界面
if __name__ == "__main__":
    main_screen()

2. 修改注册页面代码(register.py)

import sqlite3
from tkinter import *
from tkinter import messagebox
import re
import customtkinter
from PIL import ImageTk, Image

def show_register_screen():
    # 封装注册窗口为函数
    register_screen = Tk()
    register_screen.title("Register")
    register_screen.geometry("500x800")
    register_screen.resizable(width=False, height=False)
    
    # 数据库连接
    connection = sqlite3.connect("db/registration.db")
    cursor = connection.cursor()
    cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, password TEXT)")
    
    def login():
        register_screen.destroy()
        import login
        login.show_login_screen()
    
    def back_to_main():
        register_screen.destroy()
        import main
        main.main_screen()
    
    def register_user():
        username_value = username.get()
        password_value = password.get()
        
        # 密码验证逻辑
        if not re.search(r"[A-Z]", password_value):
            error_label.config(text="密码必须包含至少一个大写字母", fg="red")
            return
        if not re.search(r"\d", password_value):
            error_label.config(text="密码必须包含至少一个数字", fg="red")
            return
        if not re.search(r"\W", password_value):
            error_label.config(text="密码必须包含至少一个特殊符号", fg="red")
            return
        
        cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)", (username_value, password_value))
        connection.commit()
        connection.close()
        login()
    
    # 背景图片
    background_image_login = PhotoImage(file="assets/background2.png")
    background_label_login = Label(register_screen, image=background_image_login)
    background_label_login.place(x=0, y=0, relwidth=1, relheight=1)
    
    username = StringVar()
    password = StringVar()
    
    # Logo按钮
    logo = ImageTk.PhotoImage(Image.open("assets/Logo.png").resize((180, 130), Image.ANTIALIAS))
    logo1 = customtkinter.CTkButton(master=register_screen, image=logo, text="", compound="left", hover=False, bg_color="#020202")
    logo1.place(relx=0.48, rely=0.2, anchor=CENTER)
    
    # 用户名输入
    username_label = Label(register_screen, text="Username")
    username_label.place(relx=0.5, rely=0.3, anchor=CENTER)
    username_entry = customtkinter.CTkEntry(master=register_screen, textvariable=username, placeholder_text="Username", height=35, width=250)
    username_entry.place(relx=0.5, rely=0.35, anchor=CENTER)
    
    # 密码输入
    password_label = Label(register_screen, text="Password")
    password_label.place(relx=0.5, rely=0.4, anchor=CENTER)
    password_entry = customtkinter.CTkEntry(master=register_screen, textvariable=password, placeholder_text="Password", height=35, width=250, show="*")
    password_entry.place(relx=0.5, rely=0.45, anchor=CENTER)
    
    # 注册按钮
    register_button = customtkinter.CTkButton(master=register_screen, text="Register", command=register_user, height=35, width=250)
    register_button.place(relx=0.5, rely=0.55, anchor=CENTER)
    
    # 错误提示
    error_label = Label(register_screen, text="", fg="red")
    error_label.place(relx=0.5, rely=0.62, anchor=CENTER)
    
    # 返回按钮
    arrow_image = ImageTk.PhotoImage(Image.open("assets/hi.png").resize((50, 50), Image.ANTIALIAS))
    arrow_button = customtkinter.CTkButton(master=register_screen, image=arrow_image, text="", compound="left", fg_color='black', hover_color='black', command=back_to_main)
    arrow_button.place(relx=0.1, rely=0.1, anchor=CENTER)
    
    # 绑定图片到窗口
    register_screen.background_image_login = background_image_login
    register_screen.logo = logo
    register_screen.arrow_image = arrow_image
    
    register_screen.mainloop()
    
    connection.close()

# 仅直接运行模块时启动注册界面
if __name__ == "__main__":
    show_register_screen()

关键改进点

  • 窗口逻辑封装:每个页面的窗口创建都放在函数内,避免全局变量冲突,通过调用函数启动页面。
  • 控制模块执行时机:用if __name__ == "__main__"确保模块仅在直接运行时才启动窗口,导入时不会自动执行。
  • 图片引用保留:将图片对象绑定到窗口实例,防止被垃圾回收导致界面显示异常。
  • 明确切换逻辑:每个按钮命令都先销毁当前窗口,再调用目标页面的入口函数,流程清晰可控。

内容的提问来源于stack exchange,提问作者Joseph Wu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 16:08:10