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

Custom Tkinter切换Frame后输入框内容丢失问题求助

问题:Custom Tkinter页面切换后输入框内容丢失

切换Basic/Icon页面后,之前选择的文件路径会清空,返回原页面时输入框为空。

问题原因

  1. 每次切换重建页面:switch函数会销毁main_frame内所有子组件,再重新调用basic_page()/icon_page(),每次调用都会创建新的StringVar和输入控件,旧控件被销毁时输入数据也随之丢失。
  2. 全局变量覆盖:input_file_entry作为全局变量,切换到Icon页面时会被重新赋值为Icon页面的输入框,覆盖Basic页面的输入框引用,导致无法访问之前的控件数据。

解决方案

核心思路

  • 提前定义全局状态变量,持久保存各页面的输入数据
  • 页面仅初始化一次,切换时隐藏/显示对应页面,而非销毁重建
  • 移除易引发冲突的全局控件引用,改用绑定StringVar的方式管理输入

修改后的代码实现

1. 全局变量定义

在所有函数前定义全局的状态变量和页面实例:

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

# 全局状态变量:保存各页面输入数据
basic_input_var = StringVar()
basic_output_var = StringVar()
icon_file_var = StringVar()

# 全局页面实例:保存已创建的页面控件
basic_frame = None
icon_frame = None

2. 页面创建函数修改

页面仅初始化一次,后续切换直接显示已创建的页面:

def basic_page():
    global basic_frame

    # 页面已创建则直接显示
    if basic_frame is not None:
        basic_frame.pack(fill=BOTH, expand=True)
        return

    def choose_input_file():
        input_file = filedialog.askopenfilename(title="Select Input File")
        basic_input_var.set(input_file)

    def choose_output_file():
        output_file = filedialog.asksaveasfilename(title="Name anything...")
        basic_output_var.set(output_file)

    basic_frame = CTkFrame(main_frame)

    input_file_entry = CTkEntry(basic_frame, textvariable=basic_input_var, placeholder_text="手动输入要加密的文件路径", width=450)
    input_file_entry.pack(pady=50)

    input_file_button = CTkButton(basic_frame, text="选择输入文件", command=choose_input_file, width=150, corner_radius=40)
    input_file_button.pack()

    output_file_entry = CTkEntry(basic_frame, textvariable=basic_output_var, placeholder_text="手动输入输出文件路径(不要加.exe)", width=450)
    output_file_entry.pack(pady=50)

    output_file_button = CTkButton(basic_frame, text="另存为", command=choose_output_file, width=150, corner_radius=40)
    output_file_button.pack()

    basic_frame.pack(fill=BOTH, expand=True)

def icon_page():
    global icon_frame

    # 页面已创建则直接显示
    if icon_frame is not None:
        icon_frame.pack(fill=BOTH, expand=True)
        return

    def choose_icon_file():
        icon_path = filedialog.askopenfilename(title="选择图标", filetypes=[("图标文件", "*.ico")])
        if icon_path:
            icon_file_var.set(icon_path)
            display_icon(icon_path)

    def display_icon(icon_path):
        icon_image = Image.open(icon_path)
        icon_image = ImageTk.PhotoImage(icon_image)
        display_label.configure(image=icon_image)
        display_label.image = icon_image

    icon_frame = CTkFrame(main_frame)

    input_file_entry = CTkEntry(icon_frame, textvariable=icon_file_var, placeholder_text="图标文件路径", width=450)
    input_file_entry.pack(pady=50)

    input_file_button = CTkButton(icon_frame, text="选择.ico图标", command=choose_icon_file, width=150, corner_radius=40)
    input_file_button.pack()

    display_label = CTkLabel(icon_frame, text='')
    display_label.pack(pady=50)

    icon_frame.pack(fill=BOTH, expand=True)

3. 页面切换逻辑修改

切换时隐藏所有页面,再显示目标页面,不再销毁组件:

def hide_bg():
    basic_indicate.configure(bg_color='transparent')
    assembly_indicate.configure(bg_color='transparent')
    icon_indicate.configure(bg_color='transparent')
    build_indicate.configure(bg_color='transparent')
    advanced_indicate.configure(bg_color='transparent')

def hide_all_pages():
    # 隐藏所有已创建的页面
    if basic_frame is not None:
        basic_frame.pack_forget()
    if icon_frame is not None:
        icon_frame.pack_forget()
    # 其他页面可在此处添加

def switch(widget, page):
    hide_bg()
    widget.configure(bg_color='blue')
    hide_all_pages()
    page()

4. 主应用代码调整

主应用部分基本不变,注意补充其他页面的函数绑定:

set_appearance_mode("System")  # 模式:system(默认)、light、dark
app = CTk()

app.geometry("625x625")
app.iconbitmap('icon.ico')
app.title("FG_Crypter")

options_frame = CTkFrame(app)

basic_btn = CTkButton(options_frame, text="Basic", font=("Arial",13), width=125, command=lambda: switch(basic_indicate, basic_page))
basic_btn.place(x=0,y=0)

basic_indicate = CTkLabel(options_frame, text="", bg_color='blue', width=100, height=2)
basic_indicate.place(x=12,y=30)

icon_btn = CTkButton(options_frame, text="Icon", font=("Arial",13), width=125, command=lambda: switch(icon_indicate, icon_page))
icon_btn.place(x=125,y=0)

icon_indicate = CTkLabel(options_frame, text="", width=100, height=2)
icon_indicate.place(x=137,y=30)

# 以下为其他按钮,需替换为对应页面函数
Assembly_btn = CTkButton(options_frame, text="Assembly", font=("Arial",13), width=125, command=lambda: switch(assembly_indicate, lambda: None))
Assembly_btn.place(x=250,y=0)

assembly_indicate = CTkLabel(options_frame, text="", width=100, height=2)
assembly_indicate.place(x=262,y=30)

Advanced_btn = CTkButton(options_frame, text="Advanced", font=("Arial",13), width=125, command=lambda: switch(advanced_indicate, lambda: None))
Advanced_btn.place(x=375,y=0)

advanced_indicate = CTkLabel(options_frame, text="", width=100, height=2)
advanced_indicate.place(x=387,y=30)

Build_btn = CTkButton(options_frame, text="Build", font=("Arial",13), width=125, command=lambda: switch(build_indicate, lambda: None))
Build_btn.place(x=500,y=0)

build_indicate = CTkLabel(options_frame, text="", width=100, height=2)
build_indicate.place(x=512,y=30)

options_frame.pack(pady=5)
options_frame.propagate(False)
options_frame.configure(width=650, height=35)

main_frame = CTkFrame(app)
main_frame.pack(fill=BOTH, expand=True)

basic_page()  # 初始加载Basic页面
app.mainloop()

说明

  • 全局StringVar会持续保存用户输入,页面隐藏时数据不会丢失
  • 页面仅创建一次,切换时用pack_forget()隐藏、pack()显示,避免重复创建控件
  • 移除了易引发冲突的全局控件引用,通过StringVar直接获取输入值

内容的提问来源于stack exchange,提问作者Furjack gaming

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:55:28