【问题标题】:Tkinter auto scrolling frame almost working. Apreciate inputTkinter 自动滚动框架几乎可以工作。欣赏输入
【发布时间】:2017-04-26 18:44:14
【问题描述】:

我正在尝试在 tkinter 中开发一个可以像普通框架一样使用的可滚动框架。 感谢这个论坛中的许多提示,我开发了一些代码,如果我将滚动框打包在根窗口中,那正是它应该做的。

不幸的是,如果我使用地点或网格,它会失败。

这里是框架的代码

    import tkinter as tk

    class ScrollFrame(tk.Frame):  #this frame will be placed on a canvas that is in a frame that goes on the parent window
        class AutoScrollbar(tk.Scrollbar):
            def set(self, *args):
                if float(args[0])==0 and float(args[1])==1: self.grid_forget()
                else:
                    if self.cget('orient')=="vertical": self.grid(row=0,column=1,sticky="ns")
                    else: self.grid(row=1,column=0,sticky="ew")
                tk.Scrollbar.set(self, *args)

        def __init__(self, root,*args,**args2):
            self.outer_frame=tk.Frame(root,*args,**args2)   #this is the frame that will be packed in th parent window
            self.outer_frame.grid_columnconfigure(0, weight=1)
            self.outer_frame.grid_rowconfigure(0, weight=2)
            self.canvas = tk.Canvas(self.outer_frame, borderwidth=0, background="#ffffff")
            tk.Frame.__init__(self, self.canvas,*args,**args2)
            self.vscroll = ScrollFrame.AutoScrollbar(self.outer_frame, orient="vertical", command=self.canvas.yview)
            self.hscroll = ScrollFrame.AutoScrollbar(self.outer_frame, orient="horizontal",  command=self.canvas.xview)
            self.canvas.configure(yscrollcommand=self.vscroll.set, xscrollcommand=self.hscroll.set)

            self.canvas.create_window((0,0), window=self, anchor="nw")
            self.canvas.grid(row=0,column=0,sticky="news")
            self.hscroll.grid(row=1,column=0,sticky="ew")
            self.vscroll.grid(row=0,column=1,sticky="ns")

            self.bind("<Configure>", self.onFrameConfigure)

        def onFrameConfigure(self, event): #Adapt the scroll region   #does the resizing
            self.canvas.config(scrollregion=self.canvas.bbox("all"))
            self.canvas.config(width=event.width, height=event.height)

        #convenience functions so the ScrollFrame can be treated like a normal frame

        def destr_org(self):tk.Frame.destroy(self)
        def destroy(self):
            self.destroy=self.destr_org
            self.outer_frame.destroy()
        def pack(self,*args,**arg2):
            self.outer_frame.pack(*args,**arg2)
        def place(self,*args,**arg2):
            self.outer_frame.place(*args,**arg2)
        def grid(self,*args,**arg2):
            self.outer_frame.grid(*args,**arg2)
        def pack_forget(self,*args,**arg2):
            self.outer_frame.pack_forget(*args,**arg2)
        def place_forget(self,*args,**arg2):
            self.outer_frame.place_forget(*args,**arg2)
        def grid_forget(self,*args,**arg2):
            self.outer_frame.grid_forget(*args,**arg2)
        def config(self,*args,**arg2):
            self.outer_frame.config(*args,**arg2)
            tk.Frame.config(self,*args,**arg2)
        def configure(self,*args,**arg2):
            self.outer_frame.config(*args,**arg2)
            tk.Frame.config(self,*args,**arg2)

这里是我用来测试它的代码。只需取消注释 f.place 和 f.grid 线即可尝试。

    win=tk.Tk()
    f=ScrollFrame(win)

    for n in range(10):
        o=tk.Button(f,text="-----------------------"+str(n)+"------------------------")
        o.pack()

    f.pack(expand=True, fill=tk.BOTH)
    #f.place(x=0, y=0)
    #f.grid(column=0,row=0)    

由于我没有收到任何错误,因此我有些迷路,并且会感谢提示为什么它不起作用。 我知道有些包带有可滚动的框架,但我真的很想得到一个没有额外导入的框架。 它也确实比必要的复杂一点,但那是因为我试图以一种可以像 tk.Frame 一样填充和放置的方式来设计它

非常感谢

【问题讨论】:

  • 你永远不会布局 cons_frame。添加self.termf.pack()
  • 我也做过一次。这是我的版本:gist.github.com/novel-yet-trivial/…
  • 哦,谢谢。更正了布局。现在按钮显示,但滚动并没有更好。奇怪的是,即使 cons_frame 没有打包/显示,按钮仍然显示??
  • 所以,我用你的代码做了一个快速测试。效果很好,但似乎也有地方问题。
  • 好的,termf 的问题是我的错。它按预期工作,所以我从问题中删除了它。 ScrollFrame.place 的问题仍然存在。

标签: scroll tkinter scrollbar frame autoscroll


【解决方案1】:

好的,我想通了。 这对于 pack() 和 place() 非常有效(没有尝试让网格工作)(在 Linux 上) place() 的关键是绑定到调整父窗口的大小,而对于 pack(),调整内部框架 (=self) 的大小似乎很重要。

尽管 Novel 的代码(参见上面的 cmets)比我的要优雅得多,但如果这个代码有效,它有时会给我错误 :-)

            class ScrollFrame(tk.Frame):
                class AutoScrollbar(tk.Scrollbar):
                    def set(self, *args):
                        if float(args[0])==0 and float(args[1])==1: self.grid_forget()
                        else:
                            if self.cget('orient')=="vertical": self.grid(row=0,column=1,sticky="ns")
                            else: self.grid(row=1,column=0,sticky="ew")
                        tk.Scrollbar.set(self, *args)

                def __init__(self, root,*args,**args2):
                    self.rootwin=root
                    self.dir=tk.BOTH
                    if "dir" in args2:
                        self.dir=args2["dir"]
                        del(args2["dir"])
                    self.outer_frame=tk.Frame(root,*args,**args2)
                    self.outer_frame.grid_columnconfigure(0, weight=1)
                    self.outer_frame.grid_rowconfigure(0, weight=2)
                    self.canvas = tk.Canvas(self.outer_frame, borderwidth=0, background="#ffffff")
                    tk.Frame.__init__(self, self.canvas,*args,**args2)
                    if self.dir==tk.Y or self.dir==tk.BOTH :
                        self.vscroll = ScrollFrame.AutoScrollbar(self.outer_frame, orient="vertical", command=self.canvas.yview)
                        self.canvas.configure(yscrollcommand=self.vscroll.set)
                        self.vscroll.grid(row=0,column=1,sticky="ns")
                    if self.dir==tk.X or self.dir==tk.BOTH :
                        self.hscroll = ScrollFrame.AutoScrollbar(self.outer_frame, orient="horizontal",  command=self.canvas.xview)
                        self.canvas.configure(xscrollcommand=self.hscroll.set)
                        self.hscroll.grid(row=1,column=0,sticky="ew")
                    self.canvas.create_window((0,0), window=self, anchor="nw")
                    self.canvas.grid(row=0,column=0,sticky="news")

                    self.canvas.bind("<Enter>", self._bind_mouse)
                    self.canvas.bind("<Leave>", self._unbind_mouse)

                def onFrameConfigure(self, event): #Adapt the scroll region
                    bb=self.canvas.bbox("all")
                    self.canvas.config(scrollregion=bb)
                    self.canvas.config(height=event.height,width=event.width)
                def onRootConf(self, event):
                    bb=self.canvas.bbox("all")
                    self.canvas.config(scrollregion=bb)
                    w=bb[2]-bb[0]
                    h=bb[3]-bb[1]
                    rw=self.rootwin.winfo_width()-self.outer_frame.winfo_x()-20*int(self.vscroll.winfo_ismapped())
                    rh=self.rootwin.winfo_height()-self.outer_frame.winfo_y()-20*int(self.hscroll.winfo_ismapped())
                    if rh<h and (self.dir==tk.Y or self.dir==tk.BOTH):
                        h=rh
                    if rw<w and (self.dir==tk.X or self.dir==tk.BOTH):
                        w=rw
                    self.canvas.config(height=h,width=w)

                def destr_org(self):tk.Frame.destroy(self)
                def destroy(self):
                    self.destroy=self.destr_org
                    self.outer_frame.destroy()
                def pack(self,*args,**arg2):
                    self.bind("<Configure>", self.onFrameConfigure)
                    self.outer_frame.pack(*args,**arg2)
                def place(self,*args,**arg2):
                    self.outer_frame.place(*args,**arg2)
                    self.bind("<Configure>",self.onRootConf)
                    self.rootwin.bind("<Configure>",self.onRootConf)
                def grid(self,*args,**arg2):
                    self.outer_frame.grid(*args,**arg2)
                def pack_forget(self,*args,**arg2):
                    self.outer_frame.pack_forget(*args,**arg2)
                def place_forget(self,*args,**arg2):
                    self.outer_frame.place_forget(*args,**arg2)
                def grid_forget(self,*args,**arg2):
                    self.outer_frame.grid_forget(*args,**arg2)
                def config(self,*args,**arg2):
                    self.outer_frame.config(*args,**arg2)
                    tk.Frame.config(self,*args,**arg2)
                def configure(self,*args,**arg2):
                    self.outer_frame.config(*args,**arg2)
                    tk.Frame.config(self,*args,**arg2)
                def winfo_ismapped(self):
                    return self.outer_frame.winfo_ismapped()

                def _bind_mouse(self, event=None):
                    self.canvas.bind_all("<4>", self._on_mousewheel)
                    self.canvas.bind_all("<5>", self._on_mousewheel)
                    self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
                def _unbind_mouse(self, event=None):
                    self.canvas.unbind_all("<4>")
                    self.canvas.unbind_all("<5>")
                    self.canvas.unbind_all("<MouseWheel>")
                def _on_mousewheel(self, event):    
                    if event.num == 4 or event.delta == 120: self.canvas.yview_scroll(-1, "units" )
                    elif event.num == 5 or event.delta == -120: self.canvas.yview_scroll(1, "units" )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    • 2013-04-17
    • 1970-01-01
    相关资源
    最近更新 更多