简体   繁体   English

Python Tkinter可滚动框架类?

[英]Python Tkinter Scrollable Frame Class?

I would like to make a Tkinter class , based on the answer here , which is a Frame that automatically shows/hides Scrollbar s around the content as necessary. 我想根据此处的答案制作一个Tkinter class ,它是一个Frame ,可以根据需要自动在内容周围显示/隐藏Scrollbar

The answer that I linked to above works perfectly for my needs, with the caveat that because it's not contained within a class , it's not reusable. 我上面链接的答案非常适合我的需求,但需要注意的是,由于它不包含在class ,因此不可重用。 I figured this would be pretty quick and easy, but for some reason, my AutoScrollbar s never appear once I refactor the code into its own class , regardless of how much or little of the contents of the Frame is hidden by the window resizing. 我认为这将是非常快速和容易的,但是由于某种原因,一旦我将代码重构为自己的class ,我的AutoScrollbar不会出现,而不管窗口调整大小隐藏了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()

Here's the source for autoScrollbar , which I'm including because I import it in the above source, but I don't think the actual problem is here. 这是autoScrollbar的源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.')

You're calling canvas.config(scrollregion = canvas.bbox('all')) when the canvas is still empty, effectively making the scrollregion (0, 0, 1, 1) . 当画布仍为空时,您正在调用canvas.config(scrollregion = canvas.bbox('all')) ,从而有效地使scrollregion (0, 0, 1, 1) 0,0,1,1 (0, 0, 1, 1)

You should wait with defining the scrollregion until you have the widgets in your Frame. 您应该等待定义滚动区域,直到框架中有小部件为止。 To do that you should rename canvas to self.canvas in your AutoScrollable class and call 为此,您应该在AutoScrollable类self.canvas canvas重命名为self.canvas并调用

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

right after 之后

autoScrollable.frame.update_idletasks()

You could also bind a <Configure> event to your autoScrollable.frame which calls both the update_idletasks() and updates the scrollregion . 您还可以将<Configure>事件绑定到autoScrollable.frame ,该事件将调用update_idletasks()并更新scrollregion That way, you don't have to worry about calling it yourself anymore because they update whenever the Frame's size is changed. 这样,您不必担心自己再调用它,因为只要更改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'))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM