Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / v9 / lib / python2.4 / site-packages / Pmw / Pmw_1_2 / doc / howtobuild.html
CommitLineData
920dae64
AT
1
2 <html>
3 <head>
4 <meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
5 <meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
6 <title>How to build Pmw megawidgets</title>
7 </head>
8
9 <body bgcolor="#ffffff" text="#000000" link="#0000ee"
10 vlink="551a8b" alink="ff0000">
11
12 <h1 ALIGN="CENTER">How to build Pmw megawidgets</h1>
13
14<center><P ALIGN="CENTER">
15<IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
16</p></center>
17
18<dl>
19<dt> <h3>Introduction</h3></dt><dd>
20<p>
21 This document briefly describes how to design and code Pmw
22 megawidgets by inheriting from the Pmw base classes. It shows step
23 by step how to build a simple example megawidget. This megawidget
24 allows the user to select one of a range of numbers and it also
25 indicates if the selected number is greater than a given threshold.
26
27</p>
28
29</dd>
30<dt> <h3>Choosing the components</h3></dt><dd>
31
32<p>
33 The megawidget will be built using a Tkinter.Scale widget to allow
34 the user to select a number in a range, and a Tkinter.Frame widget
35 to act as an indicator, displaying red (say) if the selected number
36 exceeds the threshold. It will look something like this:
37
38</p>
39
40<center><P ALIGN="CENTER">
41 <IMG SRC = scale1.gif ALT = "Scale 2" WIDTH=70 HEIGHT=244>
42</p></center>
43
44<p>
45 The programmer using this megawidget will need access to the scale
46 widget, since they will need to set the scale's range. Therefore
47 the scale will be made a component of the megawidget. The
48 programmer will probably not need access to the indicator frame,
49 but, just in case the need arises to change the borderwidth or
50 relief of the indicator, we will make it a component too. This
51 illustrates a convention about components - for maximum
52 configurability, make all sub-widgets components.
53
54</p>
55
56</dd>
57<dt> <h3>Choosing the options</h3></dt><dd>
58
59<p>
60 Apart from the component options now available through the scale and indicator
61 components, the megawidget will need a few options of its own. It
62 will need a <strong>threshold</strong> option to set the threshold.
63 It may also need options to set the colors of the indicator when the
64 selected value is both above and below the threshold. Other options
65 could be <strong>orient</strong> or <strong>indicatorpos</strong> to
66 specify the relative position of components and
67 <strong>margin</strong>, <strong>padx</strong> or
68 <strong>pady</strong> to specify spacing between and around the
69 components. For this example, we will define three options -
70 <strong>threshold</strong>, <strong>colors</strong> and
71 <strong>value</strong>. The <strong>colors</strong> option will be
72 a 2-element sequence specifying two colors (below threshold, above
73 threshold). The <strong>value</strong> option will be the initial
74 value of the scale.
75
76</p>
77
78</dd>
79<dt> <h3>Coding the megawidget</h3></dt><dd>
80
81<p>
82 The first things to do are to decide on a name for the new
83 megawidget, decide which base class to inherit from and to begin to
84 write the constructor. Most Pmw megawidgets are derived from either
85 Pmw.MegaWidget, Pmw.MegaToplevel or Pmw.Dialog. In this case, since
86 the widget is not to be contained within its own toplevel window, we
87 will inherit from Pmw.MegaWidget. The constructors of megawidgets
88 take one argument (the widget to use as the parent of the
89 megawidget's hull, defaulting to the root window) and any number of
90 keyword arguments.
91
92</p>
93
94<pre>
95class ThresholdScale(Pmw.MegaWidget):
96 """ Megawidget containing a scale and an indicator.
97 """
98
99 def __init__(self, parent = None, **kw):
100</pre>
101
102<p>
103 Next, we need to define the options supplied by this megawidget.
104 Each option is specified by a 3-element sequence. The first element
105 is the option's name. The second element is the default value. The
106 third element is either a callback function,
107 <strong>Pmw.INITOPT</strong> or <strong>None</strong>. In the first
108 case, the function is called at the end of construction (during the
109 call to <code>self.inialiseoptions</code>) and also
110 whenever the option is set by a call to
111 <code>configure</code>. <strong>Pmw.INITOPT</strong> indicates that
112 the option is an initialisation option - it cannot be set by calling
113 <code>configure</code>. <strong>None</strong> indicates that the
114 option can be set by calling <code>configure</code>, but that there
115 is no callback function.
116
117</p>
118
119<p>
120 The call to <code>self.defineoptions</code> also includes the
121 keyword arguments passed in to the constructor. The value given to
122 any option specified in the keywords will override the default
123 value.
124
125</p>
126
127<pre>
128 # Define the megawidget options.
129 optiondefs = (
130 ('colors', ('green', 'red'), None),
131 ('threshold', 50, None),
132 ('value', None, Pmw.INITOPT),
133 )
134 self.defineoptions(kw, optiondefs)
135</pre>
136
137<p>
138 After defining the options, the constructor of the base class should
139 be called. The options need to be defined first so that a derived
140 class can redefine the default value of an option defined in a base
141 class. This is because the value specified by the derived class
142 must be made available before the base class constructor is called.
143 The keyword
144 arguments should not be passed into the base class constructor since
145 they have already been dealt with in the previous step.
146
147</p>
148
149<pre>
150 # Initialise base class (after defining options).
151 Pmw.MegaWidget.__init__(self, parent)
152</pre>
153
154<p>
155 Now we should create the components. The components are created as
156 children (or grandchildren ...) of the megawidget's interior.
157
158</p>
159
160<pre>
161 # Create the components.
162 interior = self.interior()
163</pre>
164
165<p>
166 The first component to create is the indicator. The
167 <code>createcomponent</code> method creates the sub-widget and
168 registers the widget as a component of this megawidget. It takes
169 five arguments plus any number of keyword arguments. The arguments
170 are name, aliases, group, class and constructor arguments. See the
171 <a href="MegaArchetype.html">Pmw.MegaArchetype reference manual</a>)
172 for full details.
173
174</p>
175
176<pre>
177 # Create the indicator component.
178 self.indicator = self.createcomponent('indicator',
179 (), None,
180 Tkinter.Frame, (interior,),
181 width = 16,
182 height = 16,
183 borderwidth = 2,
184 relief = 'raised')
185 self.indicator.grid()
186</pre>
187
188<p>
189 The scale component is created in a similar way. In this case, the
190 initial value of the scale is also set to the value of the
191 <strong>value</strong> initialisation option.
192
193</p>
194
195<pre>
196 # Create the scale component.
197 self.scale = self.createcomponent('scale',
198 (), None,
199 Tkinter.Scale, (interior,),
200 command = self._doCommand,
201 tickinterval = 20,
202 length = 200,
203 from_ = 100,
204 to = 0,
205 showvalue = 0)
206 self.scale.grid()
207
208 value = self['value']
209 if value is not None:
210 self.scale.set(value)
211</pre>
212
213<p>
214 At the end of the constructor, the <code>initialiseoptions</code>
215 method is called to check that all keyword arguments have been used
216 (that is, the caller did not specify any unknown or misspelled
217 options) and to call the option callback functions.
218
219</p>
220
221<pre>
222 # Check keywords and initialise options.
223 self.initialiseoptions()
224</pre>
225
226<p>
227 All other methods must now be defined. In this case, only one
228 method is required - a method called whenever the scale changes and
229 which sets the indicator color according to the threshold.
230
231</p>
232
233<pre>
234 def _doCommand(self, valueStr):
235 if self.scale.get() > self['threshold']:
236 color = self['colors'][1]
237 else:
238 color = self['colors'][0]
239 self.indicator.configure(background = color)
240</pre>
241
242<p>
243 To complete the megawidget, methods from other classes can be
244 copied into this class. In this case, all Tkinter.Scale methods
245 not already defined by the megawidget are made available as methods
246 of this class and are forwarded to the scale component. Note that
247 the third argument to <code>Pmw.forwardmethods</code> is the name of
248 the instance variable referring to the Tkinter.Scale widget and not
249 the name of the component. This function is called outside of and
250 after the class definition.
251
252</p>
253
254<pre>
255Pmw.forwardmethods(ThresholdScale, Tkinter.Scale, 'scale')
256</pre>
257
258<p>
259 <strong>Important note:</strong> If a megawidget defines options
260 using <code>defineoptions()</code>, then this method must be
261 called in the megawidget constructor before the call to the base
262 class constructor and a matching call to
263 <code>initialiseoptions()</code> must made at the end of the
264 constructor. For example:
265
266</p>
267<pre>
268 def __init__(self, parent = None, **kw):
269 optionDefs = ...
270 self.defineoptions(kw, optionDefs)
271 BaseClass.__init__(self, parent)
272 ...
273 self.initialiseoptions()
274</pre>
275
276</dd>
277<dt> <h3>Creating instances of the megawidget</h3></dt><dd>
278
279<p>
280 The code below creates two of our example megawidgets. The first is
281 created with default values for all options. The second is created
282 with new values for the options. It also redefines some of the
283 options of the components.
284
285</p>
286
287<dl>
288<dd>
289<pre>
290# Create and pack two ThresholdScale megawidgets.
291mega1 = ThresholdScale()
292mega1.pack(side = 'left', padx = 10, pady = 10)
293
294mega2 = ThresholdScale(
295 colors = ('green', 'yellow'),
296 threshold = 75,
297 value = 80,
298 indicator_width = 32,
299 scale_width = 25)
300mega2.pack(side = 'left', padx = 10, pady = 10)
301</pre>
302</dd>
303</dl>
304
305<center><P ALIGN="CENTER">
306 <IMG SRC = scale2.gif ALT = "Scale 1" WIDTH=150 HEIGHT=244>
307</p></center>
308
309</dd>
310<dt> <h3>The complete code</h3></dt><dd>
311
312<p>
313 The complete code for this example can be seen
314 <a href="example.py">here</a>.
315
316</p>
317
318</dd>
319<dt> <h3>Exercises</h3></dt><dd>
320
321<p>
322 These exercises build on the example presented so far.
323
324</p>
325
326<ol>
327 <li>
328 Change the call to create <code>mega1</code> so that the scale
329 widget displays the current value next to the slider. (You may
330 need to look at the Tk scale manual page to find which option to
331 the <strong>scale</strong> component to set.) You will be able to
332 do this without modifying the ThresholdScale class code.
333
334 </li>
335 <li>
336 Add a Tkinter.Label component between the indicator and scale
337 components. Modify the <code>_doCommand</code> method so that it
338 displays the current value of the scale in this label.
339
340 </li>
341 <li>
342 Modify the <strong>colors</strong> and <strong>threshold</strong>
343 options so that they both accept a tuple. Now implement multiple
344 thresholds, so that the indicator displays one of several colors,
345 depending on the value of the scale.
346
347 </li>
348 <li>
349 Add an <strong>orient</strong> initialisation option and lay out
350 the components horizontally or vertically depending on its value.
351
352 </li>
353 <li>
354 Read the description of the <code>createlabel()</code> method in
355 the <a href="MegaArchetype.html">Pmw.MegaArchetype reference
356 manual</a> and add <strong>labelpos</strong> and
357 <strong>labelmargin</strong> initialisation options which allow
358 the creation of a label for the megawidget.
359
360 </li>
361</ol>
362
363<p>
364 An example of how these changes can be made can be seen
365 <a href="exercises.py">here</a>.
366
367</p>
368
369</dd>
370<dt> <h3>Contributing your megawidgets to Pmw</h3></dt><dd>
371
372<p>
373 If you have completed a megawidget that may be useful to others, you
374 may like to consider contributing it to Pmw. See
375 <a href="starting.html#contributions">Contributions welcome</a> for
376 how to contribute.
377
378</p>
379
380</dd>
381<dt> <h3>Pmw coding conventions</h3></dt><dd>
382
383<p>
384As a final note, the Pmw code makes an attempt to follow these coding
385conventions.
386</p>
387
388<ul>
389 <li>
390 Class names: initial of each word is upper case (including first word).
391
392 </li>
393 <li>
394 Public method and function names: all in lower case.
395
396 </li>
397 <li>
398 Megawidget options: all in lower case.
399
400 </li>
401 <li>
402 Megawidget component names: all in lower case.
403
404 </li>
405 <li>
406 Function arguments: initial of each word is upper case (except first word).
407
408 </li>
409 <li>
410 Private names: initial of each word is upper case (except first
411 word if not a class)
412
413 </li>
414 <li>
415 Underscores as word separators are only used when overriding
416 Tkinter methods of same name.
417
418 </li>
419 <li>
420 Indent is four spaces.
421
422 </li>
423 <li>
424 Continuation lines are indented by eight spaces, so that they
425 won't be confused with a following nested code block.
426 Continuation lines should be used when a statement, which would
427 normally be written on one line, is longer than 80 characters.
428 Examples are "if" statements which contain many conditions and
429 function calls with many arguments.
430
431 </li>
432 <li>
433
434 Surround <code>=</code> with spaces when used with keyword
435 parameters in function calls.
436
437 </li>
438 <li>
439
440 Multi-line function calls should have one keyword parameter per
441 line.
442
443 </li>
444</ul>
445</dd>
446</dl>
447
448
449 <center><P ALIGN="CENTER">
450 <IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
451 </p></center>
452
453
454 <font size=-1>
455 <center><P ALIGN="CENTER">
456 Pmw 1.2 -
457 5 Aug 2003
458 - <a href="index.html">Home</a>
459
460 </p></center>
461 </font>
462
463 </body>
464 </html>
465