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

如何将Bryan Oakley的Tkinter PageOne类设为Mikhail ScrolledWindow的子类

问题核心原因
  • 你直接把SampleApp类本身当parent参数传递是错误的,parent需要接收父组件的实例,不是类本身
  • SampleApp.container写法错误,原代码里container是SampleApp.__init__方法内的局部变量,既不是类属性也不是实例属性,外部无法直接访问
  • 你想让PageOne获得滚动能力,应该用类继承的方式让PageOne成为ScrolledWindow的子类,而不是直接给PageOne赋值ScrolledWindow实例,语法逻辑完全错误
  • 原ScrolledWindow代码存在bug:滚动条、画布都挂载到了外层父容器上,会导致多页面切换时滚动条串页,必须先修复该问题才能正常使用
可行修改步骤

步骤1:修复ScrolledWindow的挂载逻辑

class ScrolledWindow(tk.Frame):
    """
    1. Master widget gets scrollbars and a canvas. Scrollbars are connected 
    to canvas scrollregion.

    2. self.scrollwindow is created and inserted into canvas

    Usage Guideline:
    Assign any widgets as children of <ScrolledWindow instance>.scrollwindow
    to get them inserted into canvas
    """
    def __init__(self, parent, controller, canv_w = 400, canv_h = 400, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.controller = controller
        self.parent = parent
        # 给当前滚动窗口设置行列权重,让滚动区域自适应窗口大小
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        
        # 滚动条、画布全部挂载到当前ScrolledWindow实例,不是外层parent
        self.xscrlbr = ttk.Scrollbar(self, orient = 'horizontal')
        self.xscrlbr.grid(column = 0, row = 1, sticky = 'ew')         
        self.yscrlbr = ttk.Scrollbar(self)
        self.yscrlbr.grid(column = 1, row = 0, sticky = 'ns')         
        # 创建画布
        self.canv = tk.Canvas(self, width=canv_w, height=canv_h)
        self.canv.config(relief = 'flat', bd = 2)
        self.canv.grid(column = 0, row = 0, sticky = 'nsew')
        # 关联滚动条和画布
        self.xscrlbr.config(command = self.canv.xview)
        self.yscrlbr.config(command = self.canv.yview)

        # 创建滚动内容区
        self.scrollwindow = ttk.Frame(self.canv)
        self.canv.create_window(0, 0, window = self.scrollwindow, anchor = 'nw')

        self.canv.config(xscrollcommand = self.xscrlbr.set,
                            yscrollcommand = self.yscrlbr.set,
                            scrollregion = (0, 0, 100, 100))

        self.scrollwindow.bind('<Configure>', self._configure_window)  
        self.scrollwindow.bind('<Enter>', self._bound_to_mousewheel)
        self.scrollwindow.bind('<Leave>', self._unbound_to_mousewheel)

    # 下面的方法和原代码完全一致,无需修改
    def _bound_to_mousewheel(self, event):
        self.canv.bind_all("<MouseWheel>", self._on_mousewheel)   

    def _unbound_to_mousewheel(self, event):
        self.canv.unbind_all("<MouseWheel>") 

    def _on_mousewheel(self, event):
        self.canv.yview_scroll(int(-1*(event.delta/120)), "units")  

    def _configure_window(self, event):
        size = (self.scrollwindow.winfo_reqwidth(), self.scrollwindow.winfo_reqheight())
        self.canv.config(scrollregion='0 0 %s %s' % size)
        if self.scrollwindow.winfo_reqwidth() != self.canv.winfo_width():
            self.canv.config(width = self.scrollwindow.winfo_reqwidth())
        if self.scrollwindow.winfo_reqheight() != self.canv.winfo_height():
            self.canv.config(height= self.scrollwindow.winfo_reqheight())

步骤2:修改PageOne的继承关系

让PageOne直接继承ScrolledWindow,所有页面内容挂载到self.scrollwindow即可:

class PageOne(ScrolledWindow):
    def __init__(self, parent, controller):
        # 调用父类ScrolledWindow的初始化逻辑
        super().__init__(parent, controller)
        # 所有页面内容全部放到self.scrollwindow中,不要放到self上
        label = tk.Label(self.scrollwindow, text="这是带滚动功能的Page 1", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self.scrollwindow, text="回到首页",
                            command=lambda: controller.show_frame("StartPage"))
        button.pack()
        # 可以加大量内容测试滚动效果
        for i in range(50):
            tk.Label(self.scrollwindow, text=f"测试内容行 {i+1}").pack(pady=3)

步骤3:调整SampleApp的页面注册逻辑

如果你不需要单独的ScrolledWindow测试页面,可以把循环里的ScrolledWindow去掉:

# 原代码
for F in (StartPage, PageOne, ScrolledWindow):
# 修改后
for F in (StartPage, PageOne):
效果验证

运行代码后点击首页的「Go to Page One」按钮,即可看到带滚动功能的PageOne页面,内容超过窗口高度时会自动触发滚动条,页面切换不会出现滚动条残留的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 09:09:01