【发布时间】:2018-08-06 14:24:04
【问题描述】:
在将 Python3 与 tkinter 库一起使用时,有好几次我需要一个可滚动的框架(具有垂直和水平滚动功能)来包含一组相关的小部件。由于滚动条不容易附加到框架上(我听说你可以将滚动条附加到画布上,但不能附加到框架上),我决定创建自己的 ScrolledFrame 类——一个使用滚动条和画布小部件的类,该小部件在其中显示一个框架。
在大多数情况下,它运行良好。我使用.pack() 方法布置了滚动条和画布。但是因为它们是 pack()ed,所以垂直小部件一直向下到屏幕底部,而不是留下空白区域。 (运行我的代码,看看我的意思。)
#!/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?
提前感谢您的帮助!
【问题讨论】:
标签: python python-3.x tkinter scrollbar frame