Tkinter; 如何在主窗口按钮按下时在弹出/顶层窗口中使用滚动条

2 投票
1 回答
2743 浏览
提问于 2025-04-17 23:52

我正在尝试创建一个应用程序,当在主窗口中按下一个按钮(叫做bttn)时,会打开一个带滚动条的新窗口。根据下面的代码,我需要帮助解决以下几个问题:

  • 这个滚动条应该在一个新的顶层窗口中,而不是主窗口,只有在按下bttn按钮后才会出现。
  • 这个新弹出窗口里应该包含一个名为vscrollbar的垂直滚动条,这个滚动条是在VerticalScrollFrame中定义的。
  • 这个vscrollbar滚动条不应该出现在主窗口中,只能在新的弹出窗口里显示。

    from Tkinter import * 
    class VerticalScrolledFrame(Frame):
    
    
        def __init__(self, parent, *args, **kw):
            Frame.__init__(self, parent, *args, **kw)            
    
            # create a canvas object and a vertical scrollbar for scrolling it
            vscrollbar = Scrollbar(self, orient=VERTICAL)
            vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
            canvas = Canvas(self, bd=0, highlightthickness=0,
                            yscrollcommand=vscrollbar.set)
            canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
            vscrollbar.config(command=canvas.yview)
    
            # reset the view
            canvas.xview_moveto(0)
            canvas.yview_moveto(0)
    
            # create a frame inside the canvas which will be scrolled with it
            self.interior = interior = Frame(canvas)
            interior_id = canvas.create_window(0, 0, window=interior,
                                               anchor=NW)
    
            # track changes to the canvas and frame width and sync them,
            # also updating the scrollbar
            def _configure_interior(event):
                # update the scrollbars to match the size of the inner frame
                size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
                canvas.config(scrollregion="0 0 %s %s" % size)
                if interior.winfo_reqwidth() != canvas.winfo_width():
                    # update the canvas's width to fit the inner frame
                    canvas.config(width=interior.winfo_reqwidth())
            interior.bind('<Configure>', _configure_interior)
    
            def _configure_canvas(event):
                if interior.winfo_reqwidth() != canvas.winfo_width():
                    # update the inner frame's width to fill the canvas
                    canvas.itemconfigure(interior_id, width=canvas.winfo_width())
            canvas.bind('<Configure>', _configure_canvas)
    
    
    if __name__ == "__main__":
    
        class SampleApp(Frame):
            def __init__(self,root, *args, **kwargs):
                Frame.__init__(self, root,*args, **kwargs)
    
    
                self.frame = VerticalScrolledFrame(root)
                self.frame.pack()
    
                self.widget()
    
    
            def widget(self):
                self.label = Label(text="Shrink the window to activate the scrollbar.")
                self.label.pack()
    
                bttn = Button(self.frame.interior, text = "Flytta fram/bak i listvy", command = self.open_new_window_with_text_and_scrollbar)
                bttn.pack()
    
            # Should be opened in a new, top-level, window from the main root window by pressing the #button bttn defined in widget()
            # the new popup window should contain the scrollbar vscrollbar defined in SampleApp
            # the scrollbar vscrollbar shouldn't appear in the main root window, only in the new #popup window
    
            def open_new_window_with_text_and_scrollbar(self):
    
                self.top = tk.Toplevel(self)
                frame = VerticalScrolledFrame(root)
                frame.pack()
                Button = tk.Button(self.top, text="Close window", command=self.top.destroy)
                Label = tk.Label(self.top, wraplength = 500,text="testing")
                Label.pack(side="left", fill="both", expand=True)
                Button.pack()
    
    
    
        root = tk.Tk()
        root.title("Maltparser1.0_demo")
    
        root.geometry("900x700")
        app = SampleApp(root)
        root.mainloop()
    

1 个回答

4

你把 root 当作父级传给 VerticalScrolledFrame,其实应该传 self.top

class SampleApp(Frame):

     # ...Other code...

     def open_new_window_with_text_and_scrollbar(self):
        self.top = tk.Toplevel(self)
        frame = VerticalScrolledFrame(self.top)
        frame.pack()
        # Other widgets

所以它把自己加到了主窗口 root 上,而不是 Toplevel 窗口。

撰写回答