summaryrefslogtreecommitdiff
path: root/uitools/Scrolled.py
blob: e2c1a53feb2ac351a4b384582ce71cec91688d00 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/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()