【问题标题】:Python Tkinter Scrollable Frame Class?Python Tkinter 可滚动框架类?
【发布时间】:2015-07-13 03:09:23
【问题描述】:

我想在the answer here 的基础上创建一个Tkinter class,这是一个Frame,它会根据需要在内容周围自动显示/隐藏Scrollbars。

我在上面链接的答案非常适合我的需要,但需要注意的是,因为它不包含在 class 中,所以它是不可重复使用的。我认为这将非常快速和简单,但由于某种原因,一旦我将代码重构为自己的class,我的AutoScrollbars 就永远不会出现,无论Frame 的内容有多少或很少被隐藏通过窗口调整大小。

# 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.')

【问题讨论】:

    标签: python tkinter scrollbar tkinter-canvas


    【解决方案1】:

    您在画布仍为空时调用canvas.config(scrollregion = canvas.bbox('all')),有效地使滚动区域(0, 0, 1, 1)

    您应该等待定义滚动区域,直到您的框架中有小部件。为此,您应该在 AutoScrollable 类中将 canvas 重命名为 self.canvas 并调用

    autoScrollable.canvas.config(scrollregion = autoScrollable.canvas.bbox('all'))
    

    紧接着

    autoScrollable.frame.update_idletasks()
    

    您还可以将&lt;Configure&gt; 事件绑定到您的autoScrollable.frame,它调用update_idletasks() 并更新scrollregion。这样,您就不必再担心自己调用它了,因为它们会在 Frame 的大小更改时更新。

        self.frame.bind('<Configure>', self.frame_changed)
    
    def frame_changed(self, event):
        self.frame.update_idletasks()
        self.canvas.config(scrollregion = self.canvas.bbox('all'))
    

    【讨论】:

    • 这听起来很有希望。我会尝试做出你今晚建议的一些改变,并让你知道它们是否有效(如果它们有效,我会接受并投票。)
    • 太棒了!我对其进行了测试,并且效果很好。不过,我做了一些微小的改变。我在__init__ 中定义了frameChanged,这样函数就不会可见。这意味着删除 self 参数(它现在是一个内部函数,而不是一个方法)。我将 event 参数更改为 _ 以表明它是故意未使用的。我没有将canvas 设为AutoScrollable 的属性,因此删除了所有引用它的self.s - 无需在课堂外公开它。
    • Mac 用户注意:当使用 self.frame.bind('&lt;Configure&gt;'), self.frame_changed) 和 frame_changed 方法时,包含 autoScrollable 框架的框架中的按钮(例如,在根目录中等)不会在 Mac 上显示。但是,它们确实显示在 linux 上。 (因为这是重复文件,我不认为这是由于我的错误,而且我看到其他提到的按钮未在 Mac 上显示。)使用 @fhdrsdg 的第一个建议,在 AutoScrollable 之外使用 autoScrollable.canvas.config(scrollreagion = autoScrollable.canvas.bbox('all'))类在两者上都能完美运行。谢谢你们!
    猜你喜欢
    • 1970-01-01
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-24
    • 2013-04-17
    相关资源
    最近更新 更多