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

滑动customtkinter的CTkSlider触发RecursionError的原因排查

问题分析与解决:CTkSlider值传递引发递归错误

问题背景

尝试通过独立的Variables类将CTkSlider的实时值从顶层窗口传递到主窗口,滑动滑块时触发RecursionError: maximum recursion depth exceeded错误。

错误原因分析

  1. 错误的类继承设计:Variables类错误继承了App(GUI应用主类),但Variables的定位是值传递中间层,并非GUI实例。且Variables的__init__未调用父类App的初始化方法,导致App的属性(如app_condition)未被正确初始化。
  2. 无限递归的属性访问:当value_setter中访问self.app_condition时,由于该属性未被初始化,tkinter的__getattr__方法会被触发,尝试从self.tk中查找该属性。但self.tk同样未被初始化,导致__getattr__被无限递归调用,最终触发递归深度超限错误。
  3. 无效的实例关联:ToplevelWindow中创建的Variables实例是独立于主窗口App的新对象,根本无法将滑块值传递到主窗口,完全偏离了值传递的设计目的。

修复方案

核心调整方向

  • 取消Variables对App的继承,将其改为纯数据传递类,或直接使用customtkinter内置的变量类型(如CTkIntVar)
  • 让顶层窗口持有主窗口App的实例引用,直接调用主窗口的方法更新值,建立正确的实例关联

修复后的代码示例

import customtkinter

class ToplevelWindow(customtkinter.CTkToplevel):
    def __init__(self, master_app, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.master_app = master_app  # 持有主窗口实例引用
        
        self.slider = customtkinter.CTkSlider(
            self, height=29, from_=0, to=100, number_of_steps=10,
            progress_color="#19A7CE", button_color="#FB2576",
            command=self.get_value
        )
        self.slider.grid()

    def get_value(self, value):
        # 直接调用主窗口的更新方法传递滑块值
        self.master_app.update_app_variable(int(value))

class App(customtkinter.CTk):
    def __init__(self):
        super().__init__()
        self.toplevel_window : customtkinter.CTkToplevel = None

        self.app_variable : int = 9
        self.app_variable_1 : tuple = None
        self.app_variable_2 : float = 1.5
        self.app_condition : float = 0.5

        self.button = customtkinter.CTkButton(master=self, command=self.open_toplevel)
        self.button.grid()

    def open_toplevel(self):
        if self.toplevel_window is None or not self.toplevel_window.winfo_exists():
            # 创建顶层窗口时传入主窗口实例
            self.toplevel_window = ToplevelWindow(master_app=self, master=self)
        else:
            self.toplevel_window.focus()

    def value_setter(self, size=50):
        if self.app_condition < 1:
            self.app_variable_1 = (size, size * self.app_variable_2)
        else:
            self.app_variable_1 = (size * self.app_variable_2, size)
        # 可以在这里添加打印,验证值是否更新
        print(f"更新后的app_variable_1: {self.app_variable_1}")

    def update_app_variable(self, size=50):
        self.value_setter(size)

if __name__ == "__main__":
    app = App()
    app.mainloop()

额外优化建议

如果需要更灵活的变量绑定,可以使用customtkinter的内置变量类型,示例如下:

# 在App类中定义绑定变量
self.slider_var = customtkinter.CTkIntVar(value=50)

# 顶层窗口中直接绑定该变量
self.slider = customtkinter.CTkSlider(
    self, height=29, from_=0, to=100, number_of_steps=10,
    progress_color="#19A7CE", button_color="#FB2576",
    variable=self.master_app.slider_var
)
# 主窗口可以通过trace方法监听变量变化
self.slider_var.trace_add("write", lambda *args: self.update_app_variable(self.slider_var.get()))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 00:49:54