框架的Tkinter滚动条

时间:2013-04-24 09:32:05

标签: python tkinter scrollbar frame

我的目标是将垂直滚动条添加到框架中,框架中有多个标签。一旦框架内的标签超过框架的高度,滚动条就会自动启用。搜索完毕后,我发现了this有用的帖子。根据那篇文章,我理解为了达到我想要的目的,(纠正我,如果我错了,我是初学者)我必须首先创建一个Frame,然后在里面创建一个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. 为什么我必须使用网格方法? (我尝试了放置方法,但画布上没有任何标签。)
  3. 在画布上创建窗口时使用anchor='nw'有什么特别之处?
  4. 请保持你的答案简单,因为我是初学者。

4 个答案:

答案 0 :(得分:38)

请注意,建议的代码仅适用于Python 2

以下是一个例子:

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有点棘手,似乎没有做很多。似乎没有优雅的方法来做到这一点 您的代码的一个问题是您必须手动设置画布大小 - 这就是我发布的示例代码解决的问题。

到2)
你在谈论数据功能?地方也适合我。 (一般我更喜欢网格)。

至3)
好吧,它将窗口定位在画布上。

我注意到的一件事是你的例子默认处理鼠标滚轮滚动而我发布的滚动没有。将来必须看一下。

答案 1 :(得分:20)

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

一般来说,是的,你做得对。除了画布之外,Tkinter没有本机可滚动容器。正如您所看到的,设置起来并不困难。如您的示例所示,它只需要5或6行代码即可使其工作 - 具体取决于您如何计算行数。

为什么我必须使用网格方法?(我尝试过放置方法,但画布上没有任何标签?)

你问为什么必须使用网格。不需要使用网格。可以使用地方,网格和包装。简单来说,有些更自然地适合特定类型的问题。在这种情况下,看起来你正在创建一个实际的网格 - 标签的行和列 - 所以网格是自然的选择。

在画布上创建窗口时使用anchor ='nw'有什么特别之处?

锚点告诉您窗口的哪个部分位于您给出的坐标处。默认情况下,窗口的中心将放置在坐标处。对于上面的代码,您希望左上角(“西北”)角位于坐标处。

答案 2 :(得分:10)

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

在@ Brayan Oakley的回答中使用了大量关于这个问题的答案

ScrolledWindow.scrollwindow

答案 3 :(得分:2)

即使不使用Canvas,我们也可以添加滚动条。我已经在很多其他帖子中看到它我们不能直接在框架中添加垂直滚动条等等。但是经过多次实验后发现了添加垂直滚动条以及水平滚动条的方法:)。请在下面找到用于在treeView和frame中创建滚动条的代码。

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)