布置在网格中时,滚动条小部件不起作用

时间:2018-08-06 14:24:05

标签: python python-3.x tkinter scrollbar frame

在tkinter库中使用Python3时,发生了好几次我需要一个可滚动的框架(具有垂直和水平滚动功能)才能包含一组相关的小部件。由于滚动条不容易附加到框架上(我听说您可以将滚动条附加到画布上,但是不能附加到框架上),所以我决定创建自己的ScrolledFrame类-该类使用滚动条和画布小部件,在画布小部件中显示框架。 / p>

在大多数情况下,它运行良好。我使用.pack()方法布置了滚动条和画布。但是由于它们是pack()处理的,所以垂直小部件一直向下到屏幕底部,而不是留有空白。 (运行我的代码以了解我的意思。)

#!/bin/env python3
# File:  scrolledframe.py
# Written by:  J-L


import tkinter as tk


class ScrolledFrame(tk.Frame):
    def __init__(self, parent, **kwargs):
        # Create the "scaffolding" widgets:
        self.outerFrame = outerFrame = tk.Frame(parent, **kwargs)
        self.canvas = canvas = tk.Canvas(outerFrame)
        self.vscroll = vscroll = tk.Scrollbar(outerFrame, orient='vertical')
        self.hscroll = hscroll = tk.Scrollbar(outerFrame, orient='horizontal')

        # Pack/grid the vscroll, hscroll, and canvas widgets into their frame:
        usePack = True
        if usePack:  # use .pack()
            vscroll.pack(side='right', fill='y')
            hscroll.pack(side='bottom', fill='x')
            canvas.pack(fill='both', expand=True)
        else:  # use .grid()
            canvas.grid(row=0, column=0, sticky='nsew')
            vscroll.grid(row=0, column=1, sticky='ns')
            hscroll.grid(row=1, column=0, sticky='ew')

        # Hook up the commands for vscroll, hscroll, and canvas widgets:
        vscroll.configure(command=canvas.yview)
        hscroll.configure(command=canvas.xview)
        canvas.configure(yscrollcommand=vscroll.set,
                         xscrollcommand=hscroll.set)

        # Now create this very obejct (the innerFrame) as part of the canvas:
        super().__init__(canvas)
        innerFrame = self
        canvas.create_window((0, 0), window=innerFrame)
        innerFrame.bind('<Configure>',
            lambda event: canvas.configure(scrollregion=canvas.bbox('all'),
                                           width=event.width,
                                           height=event.height))


    # Accessor methods to access the four widgets involved:
    def outer_frame(self):  return self.outerFrame
    def vscroll(self):  return self.vscroll
    def hscroll(self):  return self.hscroll
    def inner_frame(self):  return self  # (included for completeness)


    # When .pack(), .grid(), or .place() is called on this object,
    # it should be invoked on the outerFrame, attaching that to its
    # parent widget:
    def pack(self, **kwargs):  self.outerFrame.pack(**kwargs)
    def grid(self, **kwargs):  self.outerFrame.grid(**kwargs)
    def place(self, **kwargs):  self.outerFrame.place(**kwargs)


def doExample():
    # Create the main window:
    root = tk.Tk()
    root.title('ScrolledFrame Example')

    # Create the scrolledFrame and a quit button:
    scrolledFrame = ScrolledFrame(root)
    scrolledFrame.pack()
    tk.Button(root, text='Quit', command=root.quit).pack(side='bottom')

    # Create some labels to display inside the scrolledFrame:
    for i in range(1, 30+1):
        tk.Label(scrolledFrame,
                 text='This is the text inside label #{}.'.format(i)
                ).grid(row=i-1, column=0)

    # Start the GUI:
    root.mainloop()


if __name__ == '__main__':
    doExample()

说实话,这不是什么大问题,但是后来我想到了使用.grid()布局方法,即将每个滚动条放在自己的行和列中。

在代码的第18行附近,我包括了这一行:

usePack = True

如果将其从True更改为False,则滚动条和画布小部件将使用.grid()而不是.pack()进行布局,然后您将能够看到我在说什么。

因此,当我使用.grid()布置滚动条时,垂直滚动条下面的空间确实按照我的期望出现了,但是现在所有滚动条都不起作用!

对我来说这很奇怪,因为我不明白为什么简单地更改小部件的布局管理应该使它们的行为有所不同。

问题1:我在做什么而导致滚动条在.grid()布局时无法正常工作?

此外,我注意到同时使用.pack().grid()时,一旦我将窗口的大小调整为小于开始时的大小,“退出”按钮就会移出窗口

问题2:有什么方法可以迫使“退出”按钮停留在窗口上(当窗口调整大小时),而我的ScrolledFrame会受到损害吗?

在此先感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

  

我在做什么而导致滚动条在使用.grid()布局时无法正常工作?

问题在于您没有告诉grid如何处理多余的空间,以及没有足够的空间时怎么做。因此,小部件恰好占据了它们所需的空间量。

使用pack告诉它使用fillexpand选项填充所有分配的空间。使用grid,您需要为画布所在的行和列赋予非零的权重。

添加这两行,您将获得与grid相同的pack行为:

outerFrame.grid_rowconfigure(0, weight=1)
outerFrame.grid_columnconfigure(0, weight=1)

在打包fill时,您可能还想使用expandscrolledFrame选项,假设您希望它完全填满窗口。

scrolledFrame.pack(fill="both", expand=True)
  

有没有一种方法可以强制“退出”按钮停留在窗口上(当窗口调整大小时),而我的ScrolledFrame会受到损害?

在调用pack其他小部件之前,先对其调用pack。如果没有足够的空间容纳所有小部件,并且tkinter只是必须减小一个或多个小部件的大小以使其适合,则从减小最后添加的小部件的大小开始。