]> SALOME platform Git repositories - tools/eficas.git/blob - Pmw/Pmw_1_2/doc/howtobuild.html
Salome HOME
Modif V6_4_°
[tools/eficas.git] / Pmw / Pmw_1_2 / doc / howtobuild.html
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>
95 class 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>
255 Pmw.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.
291 mega1 = ThresholdScale()
292 mega1.pack(side = 'left', padx = 10, pady = 10)
293
294 mega2 = ThresholdScale(
295         colors = ('green', 'yellow'),
296         threshold = 75,
297         value = 80,
298         indicator_width = 32,
299         scale_width = 25)
300 mega2.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>
384 As a final note, the Pmw code makes an attempt to follow these coding
385 conventions.
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