框架的Python Tkinter滚动条

我的目标是添加一个垂直滚动条的框架,其中有几个标签。 滚动条应该在框架内的标签超过框架高度时自动启用。 经过search,我发现这个有用的职位。 基于这篇文章,我明白,为了实现我想要的,(纠正我,如果我错了,我是一个初学者)我必须先创build一个框架,然后创build一个canvas内的框架,并将滚动条粘到框架以及。 之后,创build另一个框架,并将其放在canvas内作为窗口对象。 所以,我终于想出了这个

from Tkinter import * def data(): for i in range(50): Label(frame,text=i).grid(row=i,column=0) Label(frame,text="my text"+str(i)).grid(row=i,column=1) Label(frame,text="..........").grid(row=i,column=2) def myfunction(event): canvas.configure(scrollregion=canvas.bbox("all"),width=200,height=200) root=Tk() sizex = 800 sizey = 600 posx = 100 posy = 100 root.wm_geometry("%dx%d+%d+%d" % (sizex, sizey, posx, posy)) myframe=Frame(root,relief=GROOVE,width=50,height=100,bd=1) myframe.place(x=10,y=10) canvas=Canvas(myframe) frame=Frame(canvas) myscrollbar=Scrollbar(myframe,orient="vertical",command=canvas.yview) canvas.configure(yscrollcommand=myscrollbar.set) myscrollbar.pack(side="right",fill="y") canvas.pack(side="left") canvas.create_window((0,0),window=frame,anchor='nw') frame.bind("<Configure>",myfunction) data() root.mainloop() 
  1. 我做对了吗? 有更好/更聪明的方式来实现这个代码给我的输出?
  2. 为什么我必须使用网格方法? (我尝试了place方法,但没有任何标签出现在canvas上。)
  3. 在canvas上创build窗口时,使用anchor ='nw'有什么特别之处?

请保持您的答案简单,因为我是一个初学者。 谢谢你的帮助。

我做对了吗?有更好/更聪明的方法来实现这个代码给我的输出?

一般来说,是的,你做对了。 除了canvas,Tkinter没有本地可滚动容器。 正如你所看到的,设置起来并不难。 正如你的例子所显示的,它只需要5或6行代码就可以工作 – 这取决于你如何计算行数。

为什么我必须使用网格方法?(我试过放置方法,但没有标签出现在canvas上?)

你问为什么你必须使用网格。 没有要求使用网格。 地方,网格和包装都可以使用。 只是有些更适合特定types的问题。 在这种情况下,它看起来像你正在创build一个实际的网格 – 行和列的标签 – 所以网格是自然的select。

在canvas上创build窗口时,使用anchor ='nw'有什么特别之处?

锚点告诉你窗口的哪个部分位于你给出的坐标上。 默认情况下,窗口的中心将被放置在坐标处。 在上面的代码的情况下,你想要左上angular(“西北”)angular落在坐标。

这里是一个例子:

 from Tkinter import * # from x import * is bad practice from ttk import * # http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame class VerticalScrolledFrame(Frame): """A pure Tkinter scrollable frame that actually works! * Use the 'interior' attribute to place widgets inside the scrollable frame * Construct and pack/place/grid normally * This frame only allows vertical scrolling """ 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(Tk): def __init__(self, *args, **kwargs): root = Tk.__init__(self, *args, **kwargs) self.frame = VerticalScrolledFrame(root) self.frame.pack() self.label = Label(text="Shrink the window to activate the scrollbar.") self.label.pack() buttons = [] for i in range(10): buttons.append(Button(self.frame.interior, text="Button " + str(i))) buttons[-1].pack() app = SampleApp() app.mainloop() 

它还没有鼠标滚轮绑定到滚动条,但它是可能的。 虽然滚动滚轮可能会有点颠簸。

编辑:

到1)
恕我直言,滚动帧在Tkinter有点棘手,似乎没有做很多。 似乎没有优雅的方式来做到这一点。
你的代码的一个问题是,你必须手动设置canvas大小 – 这就是我发布的示例代码解决了。

到2)
你在谈论数据function? 地方也适合我。 (通常我更喜欢网格)。

到3)
那么,它将窗口放在canvas上。

我注意到的一件事是,您的示例默认情况下处理鼠标滚轮滚动,而我发布的不是。 将不得不看一下这段时间。

请看我的课是一个可滚动的框架。 它的垂直滚动条也绑定到<Mousewheel>事件。 所以,你所要做的就是创build一个框架,用你喜欢的方式填充小部件,然后使这个框架成为我的ScrolledWindow.scrollwindow的子框架。 随意问,如果有什么不清楚。

@Brayan Oakley用了很多答案来解决这个问题

 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 __init__(self, parent, canv_w = 400, canv_h = 400, *args, **kwargs) docstring: Parent = master of scrolled window canv_w - width of canvas canv_h - height of canvas """ def __init__(self, parent, canv_w = 400, canv_h = 400, *args, **kwargs): """Parent = master of scrolled window canv_w - width of canvas canv_h - height of canvas """ super().__init__(parent, *args, **kwargs) self.parent = parent # creating a scrollbars self.xscrlbr = ttk.Scrollbar(self.parent, orient = 'horizontal') self.xscrlbr.grid(column = 0, row = 1, sticky = 'ew', columnspan = 2) self.yscrlbr = ttk.Scrollbar(self.parent) self.yscrlbr.grid(column = 1, row = 0, sticky = 'ns') # creating a canvas self.canv = tk.Canvas(self.parent) self.canv.config(relief = 'flat', width = 10, heigh = 10, bd = 2) # placing a canvas into frame self.canv.grid(column = 0, row = 0, sticky = 'nsew') # accociating scrollbar comands to canvas scroling self.xscrlbr.config(command = self.canv.xview) self.yscrlbr.config(command = self.canv.yview) # creating a frame to inserto to canvas self.scrollwindow = ttk.Frame(self.parent) 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.yscrlbr.lift(self.scrollwindow) self.xscrlbr.lift(self.scrollwindow) self.scrollwindow.bind('<Configure>', self._configure_window) self.scrollwindow.bind('<Enter>', self._bound_to_mousewheel) self.scrollwindow.bind('<Leave>', self._unbound_to_mousewheel) return 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): # update the scrollbars to match the size of the inner frame 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(): # update the canvas's width to fit the inner frame self.canv.config(width = self.scrollwindow.winfo_reqwidth()) if self.scrollwindow.winfo_reqheight() != self.canv.winfo_height(): # update the canvas's width to fit the inner frame self.canv.config(height = self.scrollwindow.winfo_reqheight()) 

即使不使用canvas,我们也可以添加滚动条。 我在其他许多文章中都看过,我们不能直接在框架中添加垂直滚动条等等。但经过多次实验发现,添加垂直和水平滚动条的方式:)。 请在下面的代码中find用于在TreeView和框架中创build滚动条的代码。

 f = Tkinter.Frame(self.master,width=3) f.grid(row=2, column=0, columnspan=8, rowspan=10, pady=30, padx=30) f.config(width=5) self.tree = ttk.Treeview(f, selectmode="extended") scbHDirSel =tk.Scrollbar(f, orient=Tkinter.HORIZONTAL, command=self.tree.xview) scbVDirSel =tk.Scrollbar(f, orient=Tkinter.VERTICAL, command=self.tree.yview) self.tree.configure(yscrollcommand=scbVDirSel.set, xscrollcommand=scbHDirSel.set) self.tree["columns"] = (self.columnListOutput) self.tree.column("#0", width=40) self.tree.heading("#0", text='SrNo', anchor='w') self.tree.grid(row=2, column=0, sticky=Tkinter.NSEW,in_=f, columnspan=10, rowspan=10) scbVDirSel.grid(row=2, column=10, rowspan=10, sticky=Tkinter.NS, in_=f) scbHDirSel.grid(row=14, column=0, rowspan=2, sticky=Tkinter.EW,in_=f) f.rowconfigure(0, weight=1) f.columnconfigure(0, weight=1)