Python Tkinter 可滚动框架 Class?
Python Tkinter Scrollable Frame Class?
我想在 the answer here 的基础上制作一个 Tkinter
class
,这是一个自动 shows/hides Scrollbar
的 Frame
根据需要围绕内容。
我在上面链接的答案非常适合我的需要,但需要注意的是,因为它不包含在 class
中,所以它不可重复使用。我认为这会非常快速和简单,但出于某种原因,一旦我将代码重构为它自己的 class
,我的 AutoScrollbar
就再也不会出现了,无论 AutoScrollbar
的内容有多少=16=] 被 window 调整大小隐藏。
# This class is unchanged from the other answer that I linked to,
# but I'll reproduce its source code below for convenience.
from autoScrollbar import AutoScrollbar
from Tkinter import Button, Canvas, Frame, HORIZONTAL, Tk, VERTICAL
# This is the class I made - something isn't right with it.
class AutoScrollable(Frame):
def __init__(self, top, *args, **kwargs):
Frame.__init__(self, top, *args, **kwargs)
hscrollbar = AutoScrollbar(self, orient = HORIZONTAL)
hscrollbar.grid(row = 1, column = 0, sticky = 'ew')
vscrollbar = AutoScrollbar(self, orient = VERTICAL)
vscrollbar.grid(row = 0, column = 1, sticky = 'ns')
canvas = Canvas(self, xscrollcommand = hscrollbar.set,
yscrollcommand = vscrollbar.set)
canvas.grid(row = 0, column = 0, sticky = 'nsew')
hscrollbar.config(command = canvas.xview)
vscrollbar.config(command = canvas.yview)
# Make the canvas expandable
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
# Create the canvas contents
self.frame = Frame(canvas)
self.frame.rowconfigure(1, weight = 1)
self.frame.columnconfigure(1, weight = 1)
canvas.create_window(0, 0, window = self.frame, anchor = 'nw')
canvas.config(scrollregion = canvas.bbox('all'))
# This is an example of using my new class I defined above.
# It's how I know my class isn't working quite right.
root = Tk()
autoScrollable = AutoScrollable(root)
autoScrollable.grid(row = 0, column = 0, sticky = 'news')
root.rowconfigure(0, weight = 1)
root.columnconfigure(0, weight = 1)
for i in xrange(10):
for j in xrange(10):
button = Button(autoScrollable.frame, text = '%d, %d' % (i, j))
button.grid(row = i, column = j, sticky = 'news')
autoScrollable.frame.update_idletasks()
root.mainloop()
这是 autoScrollbar
的源代码,我将其包含在上面的源代码中,但我认为实际问题不在这里。
# Adapted from here: http://effbot.org/zone/tkinter-autoscrollbar.htm
from Tkinter import Scrollbar
class AutoScrollbar(Scrollbar):
'''
A scrollbar that hides itself if it's not needed.
Only works if you use the grid geometry manager.
'''
def set(self, lo, hi):
if float(lo) <= 0.0 and float(hi) >= 1.0:
self.grid_remove()
else:
self.grid()
Scrollbar.set(self, lo, hi)
def pack(self, *args, **kwargs):
raise TclError('Cannot use pack with this widget.')
def place(self, *args, **kwargs):
raise TclError('Cannot use pack with this widget.')
您在 canvas 仍然为空时调用 canvas.config(scrollregion = canvas.bbox('all'))
,实际上使滚动区域 (0, 0, 1, 1)
.
您应该等待定义滚动区域,直到您的框架中有了小部件。为此,您应该在 AutoScrollable class 中将 canvas
重命名为 self.canvas
并调用
autoScrollable.canvas.config(scrollregion = autoScrollable.canvas.bbox('all'))
紧接着
autoScrollable.frame.update_idletasks()
您还可以将 <Configure>
事件绑定到您的 autoScrollable.frame
,它会调用 update_idletasks()
并更新 scrollregion
。这样,您就不必再担心自己调用它,因为只要框架的大小发生变化,它们就会更新。
self.frame.bind('<Configure>', self.frame_changed)
def frame_changed(self, event):
self.frame.update_idletasks()
self.canvas.config(scrollregion = self.canvas.bbox('all'))
我想在 the answer here 的基础上制作一个 Tkinter
class
,这是一个自动 shows/hides Scrollbar
的 Frame
根据需要围绕内容。
我在上面链接的答案非常适合我的需要,但需要注意的是,因为它不包含在 class
中,所以它不可重复使用。我认为这会非常快速和简单,但出于某种原因,一旦我将代码重构为它自己的 class
,我的 AutoScrollbar
就再也不会出现了,无论 AutoScrollbar
的内容有多少=16=] 被 window 调整大小隐藏。
# This class is unchanged from the other answer that I linked to,
# but I'll reproduce its source code below for convenience.
from autoScrollbar import AutoScrollbar
from Tkinter import Button, Canvas, Frame, HORIZONTAL, Tk, VERTICAL
# This is the class I made - something isn't right with it.
class AutoScrollable(Frame):
def __init__(self, top, *args, **kwargs):
Frame.__init__(self, top, *args, **kwargs)
hscrollbar = AutoScrollbar(self, orient = HORIZONTAL)
hscrollbar.grid(row = 1, column = 0, sticky = 'ew')
vscrollbar = AutoScrollbar(self, orient = VERTICAL)
vscrollbar.grid(row = 0, column = 1, sticky = 'ns')
canvas = Canvas(self, xscrollcommand = hscrollbar.set,
yscrollcommand = vscrollbar.set)
canvas.grid(row = 0, column = 0, sticky = 'nsew')
hscrollbar.config(command = canvas.xview)
vscrollbar.config(command = canvas.yview)
# Make the canvas expandable
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
# Create the canvas contents
self.frame = Frame(canvas)
self.frame.rowconfigure(1, weight = 1)
self.frame.columnconfigure(1, weight = 1)
canvas.create_window(0, 0, window = self.frame, anchor = 'nw')
canvas.config(scrollregion = canvas.bbox('all'))
# This is an example of using my new class I defined above.
# It's how I know my class isn't working quite right.
root = Tk()
autoScrollable = AutoScrollable(root)
autoScrollable.grid(row = 0, column = 0, sticky = 'news')
root.rowconfigure(0, weight = 1)
root.columnconfigure(0, weight = 1)
for i in xrange(10):
for j in xrange(10):
button = Button(autoScrollable.frame, text = '%d, %d' % (i, j))
button.grid(row = i, column = j, sticky = 'news')
autoScrollable.frame.update_idletasks()
root.mainloop()
这是 autoScrollbar
的源代码,我将其包含在上面的源代码中,但我认为实际问题不在这里。
# Adapted from here: http://effbot.org/zone/tkinter-autoscrollbar.htm
from Tkinter import Scrollbar
class AutoScrollbar(Scrollbar):
'''
A scrollbar that hides itself if it's not needed.
Only works if you use the grid geometry manager.
'''
def set(self, lo, hi):
if float(lo) <= 0.0 and float(hi) >= 1.0:
self.grid_remove()
else:
self.grid()
Scrollbar.set(self, lo, hi)
def pack(self, *args, **kwargs):
raise TclError('Cannot use pack with this widget.')
def place(self, *args, **kwargs):
raise TclError('Cannot use pack with this widget.')
您在 canvas 仍然为空时调用 canvas.config(scrollregion = canvas.bbox('all'))
,实际上使滚动区域 (0, 0, 1, 1)
.
您应该等待定义滚动区域,直到您的框架中有了小部件。为此,您应该在 AutoScrollable class 中将 canvas
重命名为 self.canvas
并调用
autoScrollable.canvas.config(scrollregion = autoScrollable.canvas.bbox('all'))
紧接着
autoScrollable.frame.update_idletasks()
您还可以将 <Configure>
事件绑定到您的 autoScrollable.frame
,它会调用 update_idletasks()
并更新 scrollregion
。这样,您就不必再担心自己调用它,因为只要框架的大小发生变化,它们就会更新。
self.frame.bind('<Configure>', self.frame_changed)
def frame_changed(self, event):
self.frame.update_idletasks()
self.canvas.config(scrollregion = self.canvas.bbox('all'))