/usr/share/doc/python-pmw-doc/html/howtobuild.html is in python-pmw-doc 1.3.2-6build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | <html>
<head>
<meta name="description" content="Pmw - a toolkit for building high-level compound widgets in Python">
<meta name="content" content="python, megawidget, mega widget, compound widget, gui, tkinter">
<title>How to build Pmw megawidgets</title>
</head>
<body bgcolor="#ffffff" text="#000000" link="#0000ee"
vlink="551a8b" alink="ff0000">
<h1 ALIGN="CENTER">How to build Pmw megawidgets</h1>
<center><P ALIGN="CENTER">
<IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
</p></center>
<dl>
<dt> <h3>Introduction</h3></dt><dd>
<p>
This document briefly describes how to design and code Pmw
megawidgets by inheriting from the Pmw base classes. It shows step
by step how to build a simple example megawidget. This megawidget
allows the user to select one of a range of numbers and it also
indicates if the selected number is greater than a given threshold.
</p>
</dd>
<dt> <h3>Choosing the components</h3></dt><dd>
<p>
The megawidget will be built using a Tkinter.Scale widget to allow
the user to select a number in a range, and a Tkinter.Frame widget
to act as an indicator, displaying red (say) if the selected number
exceeds the threshold. It will look something like this:
</p>
<center><P ALIGN="CENTER">
<IMG SRC = scale1.gif ALT = "Scale 2" WIDTH=70 HEIGHT=244>
</p></center>
<p>
The programmer using this megawidget will need access to the scale
widget, since they will need to set the scale's range. Therefore
the scale will be made a component of the megawidget. The
programmer will probably not need access to the indicator frame,
but, just in case the need arises to change the borderwidth or
relief of the indicator, we will make it a component too. This
illustrates a convention about components - for maximum
configurability, make all sub-widgets components.
</p>
</dd>
<dt> <h3>Choosing the options</h3></dt><dd>
<p>
Apart from the component options now available through the scale and indicator
components, the megawidget will need a few options of its own. It
will need a <strong>threshold</strong> option to set the threshold.
It may also need options to set the colors of the indicator when the
selected value is both above and below the threshold. Other options
could be <strong>orient</strong> or <strong>indicatorpos</strong> to
specify the relative position of components and
<strong>margin</strong>, <strong>padx</strong> or
<strong>pady</strong> to specify spacing between and around the
components. For this example, we will define three options -
<strong>threshold</strong>, <strong>colors</strong> and
<strong>value</strong>. The <strong>colors</strong> option will be
a 2-element sequence specifying two colors (below threshold, above
threshold). The <strong>value</strong> option will be the initial
value of the scale.
</p>
</dd>
<dt> <h3>Coding the megawidget</h3></dt><dd>
<p>
The first things to do are to decide on a name for the new
megawidget, decide which base class to inherit from and to begin to
write the constructor. Most Pmw megawidgets are derived from either
Pmw.MegaWidget, Pmw.MegaToplevel or Pmw.Dialog. In this case, since
the widget is not to be contained within its own toplevel window, we
will inherit from Pmw.MegaWidget. The constructors of megawidgets
take one argument (the widget to use as the parent of the
megawidget's hull, defaulting to the root window) and any number of
keyword arguments.
</p>
<pre>
class ThresholdScale(Pmw.MegaWidget):
""" Megawidget containing a scale and an indicator.
"""
def __init__(self, parent = None, **kw):
</pre>
<p>
Next, we need to define the options supplied by this megawidget.
Each option is specified by a 3-element sequence. The first element
is the option's name. The second element is the default value. The
third element is either a callback function,
<strong>Pmw.INITOPT</strong> or <strong>None</strong>. In the first
case, the function is called at the end of construction (during the
call to <code>self.inialiseoptions</code>) and also
whenever the option is set by a call to
<code>configure</code>. <strong>Pmw.INITOPT</strong> indicates that
the option is an initialisation option - it cannot be set by calling
<code>configure</code>. <strong>None</strong> indicates that the
option can be set by calling <code>configure</code>, but that there
is no callback function.
</p>
<p>
The call to <code>self.defineoptions</code> also includes the
keyword arguments passed in to the constructor. The value given to
any option specified in the keywords will override the default
value.
</p>
<pre>
# Define the megawidget options.
optiondefs = (
('colors', ('green', 'red'), None),
('threshold', 50, None),
('value', None, Pmw.INITOPT),
)
self.defineoptions(kw, optiondefs)
</pre>
<p>
After defining the options, the constructor of the base class should
be called. The options need to be defined first so that a derived
class can redefine the default value of an option defined in a base
class. This is because the value specified by the derived class
must be made available before the base class constructor is called.
The keyword
arguments should not be passed into the base class constructor since
they have already been dealt with in the previous step.
</p>
<pre>
# Initialise base class (after defining options).
Pmw.MegaWidget.__init__(self, parent)
</pre>
<p>
Now we should create the components. The components are created as
children (or grandchildren ...) of the megawidget's interior.
</p>
<pre>
# Create the components.
interior = self.interior()
</pre>
<p>
The first component to create is the indicator. The
<code>createcomponent</code> method creates the sub-widget and
registers the widget as a component of this megawidget. It takes
five arguments plus any number of keyword arguments. The arguments
are name, aliases, group, class and constructor arguments. See the
<a href="MegaArchetype.html">Pmw.MegaArchetype reference manual</a>)
for full details.
</p>
<pre>
# Create the indicator component.
self.indicator = self.createcomponent('indicator',
(), None,
Tkinter.Frame, (interior,),
width = 16,
height = 16,
borderwidth = 2,
relief = 'raised')
self.indicator.grid()
</pre>
<p>
The scale component is created in a similar way. In this case, the
initial value of the scale is also set to the value of the
<strong>value</strong> initialisation option.
</p>
<pre>
# Create the scale component.
self.scale = self.createcomponent('scale',
(), None,
Tkinter.Scale, (interior,),
command = self._doCommand,
tickinterval = 20,
length = 200,
from_ = 100,
to = 0,
showvalue = 0)
self.scale.grid()
value = self['value']
if value is not None:
self.scale.set(value)
</pre>
<p>
At the end of the constructor, the <code>initialiseoptions</code>
method is called to check that all keyword arguments have been used
(that is, the caller did not specify any unknown or misspelled
options) and to call the option callback functions.
</p>
<pre>
# Check keywords and initialise options.
self.initialiseoptions()
</pre>
<p>
All other methods must now be defined. In this case, only one
method is required - a method called whenever the scale changes and
which sets the indicator color according to the threshold.
</p>
<pre>
def _doCommand(self, valueStr):
if self.scale.get() > self['threshold']:
color = self['colors'][1]
else:
color = self['colors'][0]
self.indicator.configure(background = color)
</pre>
<p>
To complete the megawidget, methods from other classes can be
copied into this class. In this case, all Tkinter.Scale methods
not already defined by the megawidget are made available as methods
of this class and are forwarded to the scale component. Note that
the third argument to <code>Pmw.forwardmethods</code> is the name of
the instance variable referring to the Tkinter.Scale widget and not
the name of the component. This function is called outside of and
after the class definition.
</p>
<pre>
Pmw.forwardmethods(ThresholdScale, Tkinter.Scale, 'scale')
</pre>
<p>
<strong>Important note:</strong> If a megawidget defines options
using <code>defineoptions()</code>, then this method must be
called in the megawidget constructor before the call to the base
class constructor and a matching call to
<code>initialiseoptions()</code> must made at the end of the
constructor. For example:
</p>
<pre>
def __init__(self, parent = None, **kw):
optionDefs = ...
self.defineoptions(kw, optionDefs)
BaseClass.__init__(self, parent)
...
self.initialiseoptions()
</pre>
</dd>
<dt> <h3>Creating instances of the megawidget</h3></dt><dd>
<p>
The code below creates two of our example megawidgets. The first is
created with default values for all options. The second is created
with new values for the options. It also redefines some of the
options of the components.
</p>
<dl>
<dd>
<pre>
# Create and pack two ThresholdScale megawidgets.
mega1 = ThresholdScale()
mega1.pack(side = 'left', padx = 10, pady = 10)
mega2 = ThresholdScale(
colors = ('green', 'yellow'),
threshold = 75,
value = 80,
indicator_width = 32,
scale_width = 25)
mega2.pack(side = 'left', padx = 10, pady = 10)
</pre>
</dd>
</dl>
<center><P ALIGN="CENTER">
<IMG SRC = scale2.gif ALT = "Scale 1" WIDTH=150 HEIGHT=244>
</p></center>
</dd>
<dt> <h3>The complete code</h3></dt><dd>
<p>
The complete code for this example can be seen
<a href="example.py">here</a>.
</p>
</dd>
<dt> <h3>Exercises</h3></dt><dd>
<p>
These exercises build on the example presented so far.
</p>
<ol>
<li>
Change the call to create <code>mega1</code> so that the scale
widget displays the current value next to the slider. (You may
need to look at the Tk scale manual page to find which option to
the <strong>scale</strong> component to set.) You will be able to
do this without modifying the ThresholdScale class code.
</li>
<li>
Add a Tkinter.Label component between the indicator and scale
components. Modify the <code>_doCommand</code> method so that it
displays the current value of the scale in this label.
</li>
<li>
Modify the <strong>colors</strong> and <strong>threshold</strong>
options so that they both accept a tuple. Now implement multiple
thresholds, so that the indicator displays one of several colors,
depending on the value of the scale.
</li>
<li>
Add an <strong>orient</strong> initialisation option and lay out
the components horizontally or vertically depending on its value.
</li>
<li>
Read the description of the <code>createlabel()</code> method in
the <a href="MegaArchetype.html">Pmw.MegaArchetype reference
manual</a> and add <strong>labelpos</strong> and
<strong>labelmargin</strong> initialisation options which allow
the creation of a label for the megawidget.
</li>
</ol>
<p>
An example of how these changes can be made can be seen
<a href="exercises.py">here</a>.
</p>
</dd>
<dt> <h3>Contributing your megawidgets to Pmw</h3></dt><dd>
<p>
If you have completed a megawidget that may be useful to others, you
may like to consider contributing it to Pmw. See
<a href="starting.html#contributions">Contributions welcome</a> for
how to contribute.
</p>
</dd>
<dt> <h3>Pmw coding conventions</h3></dt><dd>
<p>
As a final note, the Pmw code makes an attempt to follow these coding
conventions.
</p>
<ul>
<li>
Class names: initial of each word is upper case (including first word).
</li>
<li>
Public method and function names: all in lower case.
</li>
<li>
Megawidget options: all in lower case.
</li>
<li>
Megawidget component names: all in lower case.
</li>
<li>
Function arguments: initial of each word is upper case (except first word).
</li>
<li>
Private names: initial of each word is upper case (except first
word if not a class)
</li>
<li>
Underscores as word separators are only used when overriding
Tkinter methods of same name.
</li>
<li>
Indent is four spaces.
</li>
<li>
Continuation lines are indented by eight spaces, so that they
won't be confused with a following nested code block.
Continuation lines should be used when a statement, which would
normally be written on one line, is longer than 80 characters.
Examples are "if" statements which contain many conditions and
function calls with many arguments.
</li>
<li>
Surround <code>=</code> with spaces when used with keyword
parameters in function calls.
</li>
<li>
Multi-line function calls should have one keyword parameter per
line.
</li>
</ul>
</dd>
</dl>
<center><P ALIGN="CENTER">
<IMG SRC = blue_line.gif ALT = "" WIDTH=320 HEIGHT=5>
</p></center>
<font size=-1>
<center><P ALIGN="CENTER">
Pmw 1.3 -
7 Aug 2007
- <a href="index.html">Home</a>
</p></center>
</font>
</body>
</html>
|