为什么我不能关闭名为A 的Tkinter帧,然后再创建一个?

编程语言 2026-07-12

我写了这个tkinter应用:

import os
import tkinter as tk
from tkinter import ttk

class SelectBodyScreen(ttk.Frame):

    def __init__(self,root, lang, prod_text,test_text, on_next):
        super().__init__(root)

        self.lang = lang
        self.prod_text_content = prod_text
        self.test_text_content = test_text
        self.root = root

        self.build_ui()
        self.on_next = on_next

    def next_clicked(self):
        selected_body = self.final_text.get("1.0", tk.END).strip()
        self.on_next(selected_body)

    def use_prod(self):
        text = self.prod_text.get("1.0", tk.END)
        self.final_text.delete("1.0", tk.END)
        self.final_text.insert(tk.END, text)

    def use_test(self):
        text = self.test_text.get("1.0", tk.END)
        self.final_text.delete("1.0", tk.END)
        self.final_text.insert(tk.END, text)

    def build_ui(self):
        self.lang_label = ttk.Label(self.root, text="", font=("Arial", 14, "bold"))
        self.lang_label.pack(pady=10)

        frame = ttk.Frame(self.root)
        frame.pack(fill="both", expand=True)

        # PROD
        ttk.Label(frame, text="Prod Body").grid(row=0, column=0)
        self.prod_text = tk.Text(frame, height=15, width=50)
        self.prod_text.grid(row=1, column=0, padx=5)
        self.prod_text.insert("1.0",self.prod_text_content)

        # TEST
        ttk.Label(frame, text="Test Body").grid(row=0, column=1)
        self.test_text = tk.Text(frame, height=15, width=50)
        self.test_text.grid(row=1, column=1, padx=5)
        self.test_text.insert("1.0",self.test_text_content)

        # FINAL
        ttk.Label(frame, text="Final Body").grid(row=2, column=0, columnspan=2)
        self.final_text = tk.Text(frame, height=15, width=105)
        self.final_text.grid(row=3, column=0, columnspan=2, pady=5)

        button_frame = ttk.Frame(frame)
        button_frame.grid(row=4, column=0, columnspan=2, pady=10)

        ttk.Button(button_frame, text="Use Prod",
                   command=self.use_prod).pack(side="left", padx=5)

        ttk.Button(button_frame, text="Use Test",
                   command=self.use_test).pack(side="left", padx=5)

        ttk.Button(button_frame, text="Next",
                   command=self.next_clicked).pack(side="right", padx=5)



class TemplateWizard:

    def __init__(self, root, folder, template_name_without_env, lang_order, aggregate):

        self.root = root
        self.folder = folder
        self.template_name_without_env = template_name_without_env
        self.lang_order = lang_order
        self.aggregate = aggregate

        self.lang_index = 0
        self.current_screen = None

        self.root.title("Template Wizard")
        self.root.geometry("1100x800")

        self.final = {
            "body":{
                "el":"",
                "en":""
            },
            "buttons":[]
        }

        self.show_next_language()

    def show_next_language(self):

        if self.lang_index >= len(self.lang_order):
            print("Wizard finished")
            print("Final selections:", self.aggregate.get("final", {}))
            self.root.destroy()
            return

        lang = self.lang_order[self.lang_index]

        prod_text = self.aggregate[f"prod_{self.template_name_without_env}"][lang]['body']
        test_text = self.aggregate[f"test_{self.template_name_without_env}"][lang]['body'] 

        self.current_screen = SelectBodyScreen(
            root=self.root,
            lang=lang,
            prod_text=prod_text,
            test_text=test_text,
            on_next=self.on_screen_next
        )

        self.current_screen.pack(fill="both", expand=True)

    def on_screen_next(self, selected_body):

        lang = self.lang_order[self.lang_index]

        self.final['body'][lang]=selected_body

        print(selected_body)

        # # Store selected body
        # if "final" not in self.aggregate:
        #     self.aggregate["final"] = {}

        # self.aggregate["final"][lang] = selected_body

        self.lang_index += 1
        self.current_screen.destroy()

        self.show_next_language()

我正在实现一个向导,允许我从聚合中选择一个值。

我的问题是,当我点击 next 按钮时,我得到这个:

一个 tkinter 框架被放置在另一个框架下方,且未正确关闭

并且框架没有被正确销毁。我该如何修复?

解决方案

问题在于 SelectBodyScreen 既扩展了一个框架,又通过以下方式创建了另一个框架:

        frame = ttk.Frame(self.root)

因为 SelectBodyScreen 本身也是一个框架,因此它被销毁了,但并没有在其上附加任何内容。因此,在销毁它时,你其实是在销毁一个空的框架。

一种修复方式是:

class SelectBodyScreen(ttk.Frame):

    def __init__(self,root, lang, prod_text,test_text, on_next):
        super().__init__(root)

        self.lang = lang
        self.prod_text_content = prod_text
        self.test_text_content = test_text
        self.root = root

        self.build_ui()
        self.on_next = on_next

    def next_clicked(self):
        selected_body = self.final_text.get("1.0", tk.END).strip()
        self.on_next(selected_body)

        if self.frame:
            self.frame.destroy()

    def use_prod(self):
        text = self.prod_text.get("1.0", tk.END)
        self.final_text.delete("1.0", tk.END)
        self.final_text.insert(tk.END, text)

    def use_test(self):
        text = self.test_text.get("1.0", tk.END)
        self.final_text.delete("1.0", tk.END)
        self.final_text.insert(tk.END, text)

    def build_ui(self):
        # Upon here use SELF as self-reference frame 

        self.pack(fill="both", expand=True)

        # PROD
        ttk.Label(self, text="Prod Body").grid(row=0, column=0)
        self.prod_text = tk.Text(self, height=15, width=50)
        self.prod_text.grid(row=1, column=0, padx=5)
        self.prod_text.insert("1.0",self.prod_text_content)

        # TEST
        ttk.Label(self, text="Test Body").grid(row=0, column=1)
        self.test_text = tk.Text(self, height=15, width=50)
        self.test_text.grid(row=1, column=1, padx=5)
        self.test_text.insert("1.0",self.test_text_content)

        # FINAL
        ttk.Label(self, text="Final Body").grid(row=2, column=0, columnspan=2)
        self.final_text = tk.Text(self, height=15, width=105)
        self.final_text.grid(row=3, column=0, columnspan=2, pady=5)

        button_frame = ttk.Frame(self)
        button_frame.grid(row=4, column=0, columnspan=2, pady=10)

        ttk.Button(button_frame, text="Use Prod",
                   command=self.use_prod).pack(side="left", padx=5)

        ttk.Button(button_frame, text="Use Test",
                   command=self.use_test).pack(side="left", padx=5)

        ttk.Button(button_frame, text="Next",
                   command=self.next_clicked).pack(side="right", padx=5)

正如你所见,我做了:

  1. build_ui(self): 时移除了 frame = ttk.Frame(self.root)
  2. 相反,我在 self 上挂载了任意组件,而不是使用一个框架。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章