#!/usr/bin/env python ###################################################################### # Provides a generic window containing a frame and h/v scrollbars. # Subclasses pack the scrollable/scannable thing into the frame and # hook it up to the scrollbars by invoking setView. # # Mitch Chapman #--------------------------------------------------------------------- # $Log: Scrolled.py,v $ # Revision 1.1 1996/12/01 22:58:54 mchapman # Initial revision # ###################################################################### __version__ = "$Revision: 1.1 $" import Tkinter; Tk=Tkinter import string, time ###################################################################### # This is the scrolled window class. ###################################################################### class T: ################################################################## # Specify the view to be scrolled by self. ################################################################## def _setView(self, newView): self.view = newView self.view.pack(in_=self.borderframe, fill='both', expand='yes') self.vsPacking['before'] = self.view # Attach the scrollbars. Note that scrollable must support # these methods: xview, yview, xscrollcommand, yscrollcommand. self.vscroll['command'] = self.view.yview self.hscroll['command'] = self.view.xview self.view['xscrollcommand'] = self.hscroll.set self.view['yscrollcommand'] = self.vscroll.set # Make sure the view is visible to the user # Gotta explicitly use Tk.Misc.tkraise, because if the view # is a canvas it defines its own tkraise -- whose purpose # is to change the stacking order of canvas items. Tk.Misc.tkraise(self.view, self.borderframe) ################################################################## # Initialize a new instance. ################################################################## def __init__(self, master=None, view=None): self.master = master frame = self.frame = Tk.Frame(master) # The inner frame is provided because the Tk Text widget # (<= Tk 4.1) wasn't smart enough to keep embedded windows from # drawing over its border. This inner frame can take the place # of the Text border in subclasses. self.borderframe = Tk.Frame(frame, relief='sunken', bd=3, highlightthickness=2) # Create the scrollbars. Record their packing rules for later # use in dynamically mapping/unmapping scrollbars. self.vsPacking = {'side':'right', 'fill':'y'} vs = self.vscroll = Tk.Scrollbar(frame, orient='vertical', width=12) # The horizontal scrollbar goes into its own frame at the # bottom. This offers the opportunity to stick a "spacer" # frame to the right of the horizontal bar, so both scrollbars # appear to stop at the edge of the contained view. # This is stolen from "Practical Programming in Tcl and Tk," by # Brent B. Welch. padsize = self.padsize = (string.atoi(vs['width']) + 2 *(string.atoi(vs['bd']) + string.atoi(vs['highlightthickness']))) hsFrame = self.hsFrame = Tk.Frame(frame) # Here's the "spacer" frame. hsPad = self.hsPad = Tk.Frame(hsFrame, width=padsize, height=padsize) hs = self.hscroll = Tk.Scrollbar(hsFrame, orient='horizontal', width=12) hs.pack(side='bottom', fill='x') hsPad.pack(side='right', before=self.hscroll) # This time, the packing is for self.hsFrame self.hsFramePacking = {'before':vs, 'side':'bottom', 'fill':'x', 'expand':'no'} apply(vs.pack, (), self.vsPacking) self.borderframe.pack(fill='both', expand='yes') apply(hsFrame.pack, (), self.hsFramePacking) self.view = None self.hsPacked = 1 self.vsPacked = 1 # Bad move: initializer invoking another method on self. # At least _setView is named so as to indicate that subclasses # should not override it directly... if view: self._setView(view) ################################################################## # Install a scrollable thingy as the view for self. # Note that you can change views on the fly, though it's up to # you to remove any old views before setting the new one. # newView should be a widget. It must provide Tkinter.Text-style # methods xview() and yview(), and have configurable # xscrollcommand and yscrollcommand attributes. ################################################################## def setView(self, newView): self._setView(newView) ###################################################################### # This is a scrolled text class. ###################################################################### class Text(T): ################################################################## # Initialize a new instance. ################################################################## def __init__(self, master=None): self.text = Tk.Text(master, relief='flat') T.__init__(self, master, self.text) ###################################################################### # This is a scrolled canvas class. ###################################################################### class Canvas(T): ################################################################## # Initialize a new instance. ################################################################## def __init__(self, master=None): self.canvas = Tk.Canvas(master) T.__init__(self, master, self.canvas) ###################################################################### # A List differs from other Scrolled types in that it has only a # vertical scrollbar. (This despite the fact that lists with long # entries could benefit from horizontal scrollbars...) ###################################################################### class List(T): ################################################################## # Initialize a new instance. ################################################################## def __init__(self, master=None): self.listbox = Tk.Listbox(master) T.__init__(self, master, self.listbox) self.hsFrame.forget() self.view['xscrollcommand'] = None self.hscroll['command'] = None ###################################################################### # Main function for unit testing. ###################################################################### def main(): if 0: # Here's one way to build a custom scrolled window: scroller = T(view=Tk.Text(relief='flat', wrap='none')) scroller.frame.pack(fill='both', expand='yes') scroller.frame.master.title("Second Scroller") Tk.mainloop() else: f = Tk.Frame() t = Text(f) # Turn off text wrapping so you can see the scrollbars at work. t.text.configure(width=32, height=5, wrap='none') t.text.insert('end', "This is a text.") t.frame.pack(fill='both', expand='yes') c = Canvas(f) c.canvas.configure(scrollregion="-100 -100 1000 1000") c.canvas.create_text(0, 0, text="This is a canvas.", anchor="nw") c.canvas.create_arc(300, 300, 400, 400, extent=270, fill='red') c.canvas.create_oval(100, 100, 200, 200, fill='blue') c.frame.pack(fill='both', expand='yes') l = List(f) l.listbox.insert('end', "This is a listbox.") for i in range(1, 21): l.listbox.insert('end', "%d Mississippi" % i) l.frame.pack(fill='both', expand='yes') f.master.title("Sample Scrolled Windows") f.pack() Tk.mainloop() if __name__ == "__main__": main()