在Tkinter中动态更改画布的scrollregion

时间:2012-03-18 23:14:16

标签: python tkinter

所以我有一个自定义的小部件,它继承自框架并包含一个画布和一个滚动条,以及一个自定义小部件,它也继承自我想要动态添加到画布的框架,根据需要调整滚动区域的大小。这是我的代码:

class MessageItem(Frame):
"""A message to be contained inside a scrollableContainer"""

def __init__(self, message, **kwds):
    Frame.__init__(self, **kwds)
    self.text = Label(self, text = message)
    self.text.grid(column = 0, row = 0, sticky = N+S+E+W)

class scrollableContainer(Frame):
"""A scrollable container that can contain a number of messages"""

def initContents(self):
    """Initializes a scrollbar, and a canvas that will contain all the items"""

    #the canvas that will contain all our items
    self.canv = Canvas(self)
    self.canv.grid(column = 0, row = 0, sticky = N+S+W)
    #force Tkinter to draw the canvas
    self.canv.update_idletasks()
    #use the values from the canvas being drawn to determine the size of the scroll region
    #note that currently, since the canvas contains nothing, the scroll region will be the same as 
    #the size of the canvas
    geometry = self.canv.winfo_geometry()
    xsize, ysize, xpos, ypos = parse_geometry_string(geometry) 
    self.canv['scrollregion'] = (0, 0, xsize, ysize) 

    #the scrollbar for that canvas
    self.vscroll = Scrollbar(self, orient = VERTICAL, command = self.canv.yview )
    self.vscroll.grid(column = 1, row = 0, sticky = N+S+E)

    self.canv["yscrollcommand"] = self.vscroll.set

def __init__(self, **kwds):
    Frame.__init__(self, **kwds)

    #initialize the widget's contents
    self.grid(sticky = N+S+E+W)
    self.pack()
    self.initContents()

    #initialize the list of contents so we can append to it
    self.contents = []

def addMessage(self, message):
    #Add the message to the list of contents
    self.contents.append(MessageItem(message))
    #Add the message to the grid
    self.contents[(len(self.contents) - 1)].grid(column = 0, row = (len(self.contents) - 1))
    #set the new scrollable region for the canvas
    scrollregionlist = self.canv['scrollregion'].split()
    oldRegion = int(scrollregionlist[3])
    newRegion = oldRegion + parse_geometry_string(self.contents[
        (len(self.contents) - 1)].winfo_geometry())[3]
    self.canv['scrollregion'] = (int(scrollregionlist[0]), int(scrollregionlist[1]),
        int(scrollregionlist[2]), newRegion)

我遇到的问题是self.canv ['scrollregion']似乎在 init 之外消失了。在addMessage方法中,在行中:

 scrollregionlist = self.canv['scrollregion'].split()

self.canv上的scrollregion属性返回一个空字符串,我可以通过放置

来验证
 print self.canv['scrollregion']
紧接在该行之前的

1 个答案:

答案 0 :(得分:1)

你确定Text小部件在这里不够用吗?

反正

from Tkinter import *


class MessageItem(Frame):
    """A message to be contained inside a scrollableContainer"""

    def __init__(self, master, message, **kwds):
        Frame.__init__(self, master, **kwds)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        self.text = Label(self, text=message, anchor='w', bg='gold')
        self.text.grid(row=0, column=0, sticky='nsew')

class scrollableContainer(Frame):
    """A scrollable container that can contain a number of messages"""

    def __init__(self, master, **kwargs):
        Frame.__init__(self, master, **kwargs) #holds canvas & scrollbars
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        self.canv = Canvas(self, bd=0, highlightthickness=0)
        self.hScroll = Scrollbar(self, orient='horizontal',
                                 command=self.canv.xview)
        self.hScroll.grid(row=1, column=0, sticky='we')
        self.vScroll = Scrollbar(self, orient='vertical',
                                 command=self.canv.yview)
        self.vScroll.grid(row=0, column=1, sticky='ns')
        self.canv.grid(row=0, column=0, sticky='nsew')        
        self.canv.configure(xscrollcommand=self.hScroll.set,
                            yscrollcommand=self.vScroll.set)

        self.frm = Frame(self.canv, bd=2, bg='green') #holds messages
        self.frm.grid_columnconfigure(0, weight=1)

        self.canv.create_window(0, 0, window=self.frm, anchor='nw', tags='inner')

        self.messages = []
        for i in range(20):
            m = MessageItem(self.frm, 'Something Profound', bd=2, bg='black')
            m.grid(row=i, column=0, sticky='nsew', padx=2, pady=2)
            self.messages.append(m)

        self.update_layout()        
        self.canv.bind('<Configure>', self.on_configure)

    def update_layout(self):
        self.frm.update_idletasks()
        self.canv.configure(scrollregion=self.canv.bbox('all'))
        self.canv.yview('moveto','1.0')
        self.size = self.frm.grid_size()

    def on_configure(self, event):
        w,h = event.width, event.height
        natural = self.frm.winfo_reqwidth()
        self.canv.itemconfigure('inner', width= w if w>natural else natural)
        self.canv.configure(scrollregion=self.canv.bbox('all'))

    def add_message(self, message):
        m = MessageItem(self.frm, message, bd=2, bg='red')
        m.grid(row=self.size[1], column=0, padx=2, pady=2, sticky='we')
        self.messages.append(m)
        self.update_layout()


root = Tk()
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
sc = scrollableContainer(root, bd=2, bg='black')
sc.grid(row=0, column=0, sticky='nsew')

def new_message():
    test = 'Something Profane'
    sc.add_message(test)

b = Button(root, text='New Message', command=new_message)
b.grid(row=1, column=0, sticky='we')

root.mainloop()