Python 关闭顶层窗口后在主窗口中滚动时出错

Python 关闭顶层窗口后在主窗口中滚动时出错,python,tkinter,tkinter-canvas,Python,Tkinter,Tkinter Canvas,我正在使用Tkinter构建应用程序,我需要可滚动的窗口。我使用画布创建了一个可滚动的容器:ScrollContainer。在此之后,我将程序的主要逻辑合并到这个容器中,在其中我放置了一个按钮,打开另一个单独的顶级窗口。这个单独的窗口也必须是可滚动的。因此,我还将其包含在同一容器类中 现在,问题是:当我运行程序时,我的主窗口滚动良好。单击按钮后,我打开顶层窗口。辅助窗口滚动良好。在我关闭辅助窗口并将鼠标再次悬停在主窗口上后,现在它不会滚动,并且控制台中出现错误: Exception in Tki

我正在使用Tkinter构建应用程序,我需要可滚动的窗口。我使用画布创建了一个可滚动的容器:ScrollContainer。在此之后,我将程序的主要逻辑合并到这个容器中,在其中我放置了一个按钮,打开另一个单独的顶级窗口。这个单独的窗口也必须是可滚动的。因此,我还将其包含在同一容器类中

现在,问题是:当我运行程序时,我的主窗口滚动良好。单击按钮后,我打开顶层窗口。辅助窗口滚动良好。在我关闭辅助窗口并将鼠标再次悬停在主窗口上后,现在它不会滚动,并且控制台中出现错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\mirel.voicu\Anaconda3\envs\gis385\lib\tkinter\__init__.py", line 1883, in __call__
    return self.func(*args)
  File "C:/Users/mirel.voicu/Desktop/python_projects/TKINTER/standalone_program/test.py", line 45, in _on_mousewheel
    self.my_canvas.yview_scroll(int(-1*(event.delta/120)), "units")
  File "C:\Users\mirel.voicu\Anaconda3\envs\gis385\lib\tkinter\__init__.py", line 1929, in yview_scroll
    self.tk.call(self._w, 'yview', 'scroll', number, what)
_tkinter.TclError: invalid command name ".!toplevel.!frame.!canvas"

注意: 我也尝试了使用
self.my\u canvas.bind(“,self.\u在鼠标滚轮上)
而不是
self.my\u canvas.bind(“,self.\u在鼠标滚轮上)
,现在没有错误。但是,滚动改变了。如果将鼠标悬停在标签上,则无法再滚动。只有将窗口放大并将鼠标悬停在右侧一点,才能滚动。我猜这是因为你必须把鼠标放在画布上,因为它是唯一可以滚动的实体

ScrollContainer类别:

from tkinter import *
from tkinter import ttk


class ScrollContainer (ttk.Frame):
    def __init__(self, container,w,h,*args, **kwargs):
        super().__init__(container, *args, **kwargs)

        # Create a main frame

        self.main_frame = Frame(container, width=w, height=h)
        self.main_frame.pack(side=TOP,fill=BOTH, expand=1)  # expand frame to the size of the container


        # create a canvas

        self.my_canvas = Canvas(self.main_frame)
        self.my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
        self.my_canvas.bind_all("<MouseWheel>", self._on_mousewheel)

        # add h and v scrollbar to canvas

        self.my_vscrollbar = ttk.Scrollbar(self.main_frame, orient=VERTICAL, command=self.my_canvas.yview)
        self.my_vscrollbar.pack(side=RIGHT, fill=Y)

        self.my_hscrollbar = ttk.Scrollbar(container, orient=HORIZONTAL, command=self.my_canvas.xview)
        self.my_hscrollbar.pack(side=BOTTOM, fill=X)

        # configure canvas
        self.my_canvas.configure(yscrollcommand=self.my_vscrollbar.set, xscrollcommand=self.my_hscrollbar.set)
        self.my_canvas.bind('<Configure>', lambda e: self.my_canvas.configure(scrollregion=self.my_canvas.bbox('all')))

        # create another frame inside the canvas
        self.second_frame = Frame(self.my_canvas)

        # add that new frame to a window in the canvas
        self.my_canvas.create_window((0, 0), window=self.second_frame, anchor='nw')

    def _on_mousewheel(self, event):

        self.my_canvas.yview_scroll(int(-1*(event.delta/120)), "units")

这是因为您使用了
bind\u all()
,这是一种基于应用程序的绑定。因此,
Toplevel()
中的绑定将覆盖
根目录中的绑定。当toplevel被销毁时,绑定函数仍在引用toplevel中的画布,因此出现异常

您应该使用窗口绑定:

类滚动容器(ttk.Frame):
定义初始化(self,container,w,h,*args,**kwargs):
super()
container.bind(“,self._在鼠标滚轮上)#在父窗口上绑定
#创建一个主框架
self.main_frame=frame(容器,宽度=w,高度=h)
self.main_frame.pack(side=TOP,fill=BOTH,expand=1)#将框架扩展到容器的大小
#创建画布
self.my_canvas=画布(self.main_框架)
self.my_canvas.pack(side=LEFT,fill=BOTH,expand=1)
#self.my\u canvas.bind\u all(“,self.\u在鼠标滚轮上)
#将h和v滚动条添加到画布
self.my\u vscrollbar=ttk.Scrollbar(self.main\u frame,orient=VERTICAL,command=self.my\u canvas.yview)
self.my_vscrollbar.pack(side=RIGHT,fill=Y)
self.my\hscrollbar=ttk.Scrollbar(容器,方向=水平,命令=self.my\u canvas.xview)
self.my\hscrollbar.pack(侧面=底部,填充=X)
#配置画布
self.my_canvas.configure(yscrollcommand=self.my_vscrollbar.set,xscrollcommand=self.my_hscrollbar.set)
self.my\u canvas.bind(“”,lambda e:self.my\u canvas.configure(scrollregion=self.my\u canvas.bbox('all'))
#在画布内创建另一个框架
self.second\u frame=frame(self.my\u画布)
#将新框架添加到画布中的窗口
self.my\u canvas.create\u window((0,0),window=self.second\u frame,anchor='nw')
鼠标滚轮上的def(自身、事件):
self.my_canvas.yview_滚动条(int(-1*(event.delta/120)),“单位”)

这是因为您使用了
bind\u all()
,这是一种基于应用程序的绑定。因此,
Toplevel()
中的绑定将覆盖
根目录中的绑定。当toplevel被销毁时,绑定函数仍在引用toplevel中的画布,因此出现异常

您应该使用窗口绑定:

类滚动容器(ttk.Frame):
定义初始化(self,container,w,h,*args,**kwargs):
super()
container.bind(“,self._在鼠标滚轮上)#在父窗口上绑定
#创建一个主框架
self.main_frame=frame(容器,宽度=w,高度=h)
self.main_frame.pack(side=TOP,fill=BOTH,expand=1)#将框架扩展到容器的大小
#创建画布
self.my_canvas=画布(self.main_框架)
self.my_canvas.pack(side=LEFT,fill=BOTH,expand=1)
#self.my\u canvas.bind\u all(“,self.\u在鼠标滚轮上)
#将h和v滚动条添加到画布
self.my\u vscrollbar=ttk.Scrollbar(self.main\u frame,orient=VERTICAL,command=self.my\u canvas.yview)
self.my_vscrollbar.pack(side=RIGHT,fill=Y)
self.my\hscrollbar=ttk.Scrollbar(容器,方向=水平,命令=self.my\u canvas.xview)
self.my\hscrollbar.pack(侧面=底部,填充=X)
#配置画布
self.my_canvas.configure(yscrollcommand=self.my_vscrollbar.set,xscrollcommand=self.my_hscrollbar.set)
self.my\u canvas.bind(“”,lambda e:self.my\u canvas.configure(scrollregion=self.my\u canvas.bbox('all'))
#在画布内创建另一个框架
self.second\u frame=frame(self.my\u画布)
#将新框架添加到画布中的窗口
self.my\u canvas.create\u window((0,0),window=self.second\u frame,anchor='nw')
鼠标滚轮上的def(自身、事件):
self.my_canvas.yview_滚动条(int(-1*(event.delta/120)),“单位”)

很酷。它起作用了。非常感谢您的回复。它起作用了。非常感谢您的回复
def open():

    w=Toplevel()
    SecondContainer=ScrollContainer(w,1000,768)

    for thing in range(40):
        Label(SecondContainer.second_frame, text=f"It's Friday {thing} ").grid(row=thing, column=0)

root=Tk()

MainContainer=ScrollContainer(root,1000,768)

btn=Button(MainContainer.second_frame, text="New Window",bg='yellow',command=open)
btn.grid(row=0,column=0)


for thing in range(1,30):
    Label(MainContainer.second_frame,text=f"It's Friday {thing} ").grid(row=thing,column=0)

 # frame design

root.mainloop()