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

CustomTkinter字典程序:翻页按钮与开关交互报错排查

字典程序翻页后开关操作报错问题及解决方法

我使用CustomTkinter开发一款字典程序,程序包含翻页按钮与功能开关。点击翻页按钮会销毁前10组组件并生成新10组以实现分页效果。先开启开关再点击翻页按钮无报错,但先点击翻页按钮再操作开关则会触发报错。开关用于批量激活组件内的编辑按钮,以下是可复现的简化代码:

import customtkinter

customtkinter.set_appearance_mode('light')
customtkinter.set_default_color_theme('dark-blue')

root = customtkinter.CTk()
root.geometry('750x800')
root.title('My dictionary')
root.resizable(width=False, height=False)


database_example = (
    [1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4], [5, 5, 5], [6, 6, 6], [7, 7, 7], [8, 8, 8], [9, 9, 9],
    [10, 10, 10], [11, 11, 11], [12, 12, 12], [13, 13, 13], [14, 14, 14], [15, 15, 15], [16, 16, 16],
    [17, 17, 17], [18, 18, 18], [19, 19, 19], [20, 20, 20], [21, 21, 21], [22, 22, 22], [23, 23, 23],
    [24, 24, 24], [25, 25, 25], [26, 26, 26], [27, 27, 27], [28, 28, 28], [29, 29, 29], [30, 30, 30],
    [31, 31, 31], [32, 32, 32], [33, 33, 33], [34, 34, 34], [35, 35, 35], [36, 36, 36], [37, 37, 38],
    [39, 39, 39], [40, 40, 40]
)

start_pos = 0
end_pos = 10


class WordBox:
    button_container = []
    instances = []

    def __init__(self,
                 word='',
                 translation='',
                 context='',
                 ):
        self.instances.append(self)
        word_fontsize = 23
        translation_fontsize = 23

        self.outer_frame = customtkinter.CTkFrame(master=scroll_frame, width=700, height=150, fg_color='#AED5D5')
        self.outer_frame.pack(pady=12, padx=10, side='top')

        self.inner_LabelWord = customtkinter.CTkLabel(master=self.outer_frame,
                                                      text=word,
                                                      fg_color='#C9D1D8',
                                                      text_color='#0B7BDE',
                                                      font=('Arial Black', word_fontsize),
                                                      width=450, height=50, anchor='nw')
        self.inner_LabelWord.grid(row=0, column=0)

        self.inner_LabelTranslation = customtkinter.CTkLabel(master=self.outer_frame,
                                                             text=translation,
                                                             fg_color='#C9D1D8',
                                                             text_color='black',
                                                             font=('Yu Gothic UI Semibold', translation_fontsize),
                                                             width=450, height=50, anchor='nw')
        self.inner_LabelTranslation.grid(row=1, column=0)
        self.inner_LabelContext = customtkinter.CTkLabel(master=self.outer_frame,
                                                         text=context,
                                                         fg_color='#908D8B',
                                                         text_color='black',
                                                         font=('Dubai', 14),
                                                         width=450, height=50, anchor='nw')
        self.inner_LabelContext.grid(row=2, column=0)
        self.inner_PicFrame = customtkinter.CTkFrame(master=self.outer_frame, fg_color='#48E5E0', width=150, height=150)
        self.inner_PicFrame.grid(row=0, column=1, rowspan=3)
        self.inner_PicLabel = customtkinter.CTkLabel(master=self.inner_PicFrame, text='PICTURE')
        self.inner_PicLabel.pack()

        self.inner_Button = customtkinter.CTkButton(master=self.outer_frame, width=50, height=150, text='O',
                                                    font=('', 20), fg_color='#C9D1D8', hover_color='#FFA60B',
                                                    state='disabled')
        self.inner_Button.grid(row=0, column=2, rowspan=3)
        self.button_container.append(self.inner_Button)


def switcher():
    if switch_var.get() == 'on':
        for i in WordBox.button_container:
            i.configure(state='normal')
    if switch_var.get() == 'off':
        for i in WordBox.button_container:
            i.configure(state='disabled')


def start_programm(db):
    for word in db[:10]:
        WordBox(
            word=word[0],
            translation=word[1],
            context=word[2],
        )


def rightbutton():
    global start_pos
    global end_pos
    start_pos += 10
    end_pos += 10
    for item in WordBox.button_container:
        del item
    for instance in WordBox.instances:
        instance.inner_Button.destroy()
        instance.outer_frame.destroy()
        instance.inner_PicFrame.destroy()
        instance.inner_LabelContext.destroy()
        instance.inner_LabelTranslation.destroy()
        instance.inner_LabelWord.destroy()
        del instance

    for word in database_example[start_pos:end_pos]:
        WordBox(
            word=word[0],
            translation=word[1],
            context=word[2],
        )


switch_var = customtkinter.StringVar(value="off")
switch = customtkinter.CTkSwitch(master=root, text='', command=switcher,
                                 variable=switch_var, onvalue="on", offvalue="off",
                                 progress_color='#E5611F')
switch.place(relx=0.862, rely=0.26)

scroll_frame = customtkinter.CTkScrollableFrame(master=root, width=700, height=500)
scroll_frame.place(relx=0.01, rely=0.3)


right_button = customtkinter.CTkButton(master=root, text='>>', command=rightbutton, width=35, height=30,
                                       corner_radius=17, fg_color='#817A7A', hover_color='#E5611F')
right_button.place(relx=0.12, rely=0.26)


start_programm(database_example)

root.mainloop()

解决方案

原代码中del运算符未按预期清空容器内的引用,导致翻页后button_container和instances中仍残留已销毁组件的无效引用,操作开关时会尝试访问这些无效对象引发报错。重写翻页按钮的回调函数,使用clear()方法彻底清空两个容器,问题得以解决,重写后的函数如下:

def rightbutton():
    global start_pos
    global end_pos
    start_pos += 10
    end_pos += 10

    for instance in WordBox.instances:
        instance.inner_Button.destroy()
        instance.outer_frame.destroy()
        instance.inner_PicFrame.destroy()
        instance.inner_LabelContext.destroy()
        instance.inner_LabelTranslation.destroy()
        instance.inner_LabelWord.destroy()
    WordBox.button_container.clear()
    WordBox.instances.clear()
    for word in database_example[start_pos:end_pos]:
        WordBox(
            word=word[0],
            translation=word[1],
            context=word[2],
        )

内容的提问来源于stack exchange,提问作者mr.Jenkins

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 18:07:02