当前位置: 首页 > 知识库问答 >
问题:

用于帧的Tkinter滚动条

诸新霁
2023-03-14

我的目标是在一个有几个标签的框架中添加一个垂直滚动条。当框架内的标签超过框架的高度时,滚动条应该自动启用。经过搜索,我发现了这个有用的帖子。根据那篇文章,我明白为了实现我想要的,(如果我错了,请纠正我,我是一个初学者)我必须先创建一个框架,然后在框架内创建一个画布,并粘贴滚动条到那个框架。之后,创建另一个框架,并将其作为窗口对象放在画布内。所以,我终于想出了这个:

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方法,但没有一个标签出现在画布上。)
  3. 在画布上创建窗口时,使用锚有什么特别之处?

请保持你的答案简单,因为我是初学者。

共有3个答案

华凯捷
2023-03-14

请看我的类,这是一个可滚动的框架。它的垂直滚动条绑定到

从@Brayan Oakley answers中使用了很多来接近这个问题

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())

吴弘壮
2023-03-14

“我做得对吗?有没有更好/更聪明的方法来实现这段代码给我的输出?”

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

为什么我必须使用网格方法?(我尝试了地方方法,但没有一个标签出现在画布上?)"

您询问为什么必须使用网格。没有使用网格的要求。地点、网格和包装均可使用。简单地说,有些更适合于特定类型的问题。在本例中,看起来您正在创建一个实际的网格——标签的行和列——因此网格是自然选择。

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

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

桓嘉谊
2023-03-14

请注意,建议的代码仅对Python2有效

以下是一个例子:

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)
您正在谈论数据函数?这个地方也适合我。(一般来说,我更喜欢网格)。

to 3)
嗯,它将窗口定位在画布上。

我注意到的一点是,您的示例默认处理鼠标滚轮滚动,而我发布的示例则不处理。总有一天会看到的。

 类似资料:
  • 我无法让x和y滚动条在使用Python的Tkinter中工作,尽管我已经遵循了多个示例: 如何在python 3.4中使用tkinter添加2个滚动条 在tkinter中添加滚动条到一组小部件 如何在tkinter中制作一个合适的双滚动条框架 垂直和水平滚动条上的Tkinter小部件 水平和垂直滚动画布小部件 滚动条会出现,但当窗口小于框架时不会激活。我怎样才能让它工作(见下图)? 下面是产生我的

  • 问题内容: 我的目标是向具有多个标签的框架添加垂直滚动条。一旦框架内的标签超过框架的高度,滚动条应自动启用。搜索之后,我发现了这个有用的帖子。根据该帖子,我了解到要实现我想要的功能(如果我错了,请纠正我,我是一个初学者),我必须先创建一个,然后在该框架内创建一个并将滚动条粘贴到该框架上好。之后,创建另一个框架并将其作为窗口对象放在画布内。所以,我终于想出了这个: 我做对了吗?有没有更好/更聪明的方

  • Scrollbar 控件常用于创建一个水平或者垂直的滚动条,通常情况下,Scrollbar 控件可以与 Listbox、Text、Canvas 以及 Entry 等控件一起使。 滚动条控件是 GUI  程序中经常使用的一种控件类型,它主要用来控制控件区域的可见范围,比如当 Text 控件的文本内容非常多时,为了方便用户阅读,可以给 Text 控件增加滚动条,用户只需拖动滚动条就能完成内容的阅读。

  • 问题内容: 因此,经过数小时或阅读文章并查看tkinter的文档后,我发现在Windows机器上,tkinter滚动条的颜色选项将无法使用,因为滚动条直接从Windows获取其主题。我的问题是默认主题的颜色确实与我的程序冲突,因此我试图找到一种不涉及导入其他GUI程序包(例如PyQt)的解决方案(我无法在工作中访问pip,所以这是一个问题以获取新软件包) 除了使用单独的程序包之外,任何人都可以向我

  • 问题内容: 我的目标是让滚动条位于全屏窗口的右侧,允许用户在各种不同的小部件(例如标签和按钮)中上下滚动。从我在该站点上看到的其他答案中,我得出的结论是,必须将滚动条分配给画布才能使其正常运行,我已经尝试将其包含在代码中,但还没有太多成功。 以下代码显示了到目前为止我已完成的工作的简化版本: 运行此代码时,我面临两个问题: 一种是滚动条处于非活动状态,并且不允许用户向下滚动以查看其余文本。 另一个

  • 问题内容: 我试图让使用Tkinter的一个UI,我有问题要放三里。 我有一个名为的数组,其中包含一些名称:。我想创建3个LabelFrames,每个都有一个。我为它创建了一个,但是它只显示最后一个窗口的Scroll: 那么,如何修改代码以显示每个滚动条? 这是创建窗口的代码部分: 提前致谢。 问题答案: 您创建了3个canvas,但是所有画布都设置在self.canvas中。 因此self.ca