Python
and
Tkinter
Programming
John E. Grayson
M A N N I N G
Graphical user interfaces for Python programs
Python and Tkinter
Programming
J
OHN
E. G
RAYSON
M A N N I N G
Greenwich (74° w. long.)For online information and ordering of this and other Manning books, go to www.manning.com. The publisher offers discounts on this book when ordered in quantity. For more information, please contact:
Special Sales Department Manning Publications Co.
32 Lafayette Place Fax: (203) 661-9018 Greenwich, CT 06830 email: [email protected]
©2000 by Manning Publications Co. All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by means electronic, mechanical, photocopying, or otherwise, without prior written permission of the publisher.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in the book, and Manning Publications was aware of a trademark claim, the designations have been printed in initial caps or all caps.
Recognizing the importance of preserving what has been written, it is Manning’s policy to have the books we publish printed on acid-free paper, and we exert our best efforts to that end.
Manning Publications Co. Copyeditor: Kristen Black 32 Lafayette Place Typesetter: Dottie Marsico Greenwich, CT 06830 Cover designer: Leslie Haimes
Second corrected printing 2000 Printed in the United States of America
vii
brief contents
preface xv
special thanks xvii
about the reader xix
about the author xx
conventions xxi
about the cover xxii
author online xxiii
Part I Basic concepts 1
1
Python 3
2
Tkinter 12
3
Building an application 18
Part 2 Displays 29
4
Tkinter widgets 31
5
Screen layout 77
6
Events, bindings and callbacks 95
7
Using classes, composites and special widgets 120
8
Dialogs and forms 140
9
Panels and machines 199
10
Drawing blobs and rubber lines 237
11
Graphs and charts 276
12
Navigation 300
viii
B R I E F C O N T E N T SPart 3 Putting it all together... 311
14
Extending Python 313
15
Debugging applications 329
16
Designing effective graphics applications 338
17
Programming for performance 348
18
Threads and asynchronous techniques 361
19
Distributing Tkinter applications 374
Part 4 Appendices 381
appendix A Mapping Tk to Tkinter 383
appendix B Tkinter reference 425
appendix C Pmw reference: Python megawidgets 542
appendix D Building and installing Python, Tkinter 610
appendix E Events and keysyms 617
appendix F Cursors 621
appendix G References 625
index 629
ix
contents
preface xv
special thanks xvii
about the reader xix
about the author xx
conventions xxi
about the cover xxii
author online xxiii
Part I Basic concepts 1
1
Python 3
1.1 Introduction to Python programming and a feature review 3
Why Python? 4, Where can Python be used? 5
1.2 Key data types: lists, tuples and dictionaries 5
Lists 5, Tuples 7, Dictionaries 8
1.3 Classes 9
How do classes describe objects? 9, Defining classes 9, Neat Python trick #109, Initializing an instance 10, Methods 10, Private and public variables and methods 11, Inheritance 11, Multiple inheritance 11, Mixin classes 11
2
Tkinter 12
2.1 The Tkinter module 12
What is Tkinter? 12, What about performance? 13, How do I use Tkinter? 13, Tkinter features 14
2.2 Mapping Tcl/Tk to Tkinter 14 2.3 Win32 and UNIX GUIs 15
x
CONTENTS2.4 Tkinter class hierarchy 16 2.5 Tkinter widget appearance 17
3
Building an application 18
3.1 Calculator example: key features 21 3.2 Calculator example: source code 21 3.3 Examining the application structure 27 3.4 Extending the application 28
Part 2 Displays 29
4
Tkinter widgets 31
4.1 Tkinter widget tour 31
Toplevel 32, Frame 33, Label 35, Button 36, Entry 37,
Radiobutton 37, Checkbutton 38, Menu 39, Message 42, Text 43, Canvas 44, Scrollbar 45, Listbox 45, Scale 46
4.2 Fonts and colors 47
Font descriptors 47, X Window System font descriptors 47, Colors 48, Setting application-wide default fonts and colors 49
4.3 Pmw Megawidget tour 49
AboutDialog 50, Balloon 50, ButtonBox 51, ComboBox 52, ComboBoxDialog 53, Counter 54, CounterDialog 55, Dialog 56, EntryField 56, Group 57, LabeledWidget 58, MenuBar 59, MessageBar 59, MessageDialog 61, NoteBookR 61, NoteBookS 62, NoteBook 63, OptionMenu 64, PanedWidget 65, PromptDialog 66, RadioSelect 66, ScrolledCanvas 67, ScrolledField 68, ScrolledFrame 69, ScrolledListbox 70, ScrolledText 70, SelectionDialog 71, TextDialog 72, TimeCounter 73
4.4 Creating new megawidgets 73
Description of the megawidget 73, Options 74, Creating the megawidget class 74
5
Screen layout 77
5.1 Introduction to layout 77
Geometry management 78
5.2 Packer 79
Using the expand option 82, Using the fill option 82, Using the padx and pady options 84, Using the anchor option 84, Using hierarchical packing 84
5.3 Grid 86 5.4 Placer 90 5.5 Summary 94
C O N T EN T S
xi
6
Events, bindings and callbacks 95
6.1 Event-driven systems: a review 95
What are events? 96, Event propagation 97, Event types 97
6.2 Tkinter events 98
Events 98
6.3 Callbacks 102
6.4 Lambda expressions 103
Avoiding lambdas altogether 103
6.5 Binding events and callbacks 104
Bind methods 104, Handling multiple bindings 106
6.6 Timers and background procedures 107 6.7 Dynamic callback handlers 107
6.8 Putting events to work 108
Binding widgets to dynamic data 108, Data verification 111, Formatted (smart) widgets 117
6.9 Summary 119
7
Using classes, composites and special widgets 120
7.1 Creating a Light Emitting Diode class 120
Let’s try that again 126, What has changed? 129
7.2 Building a class library 129
Adding a hex nut to our class library 131, Creating a switch class 133, Building a MegaWidget 136
7.3 Summary 139
8
Dialogs and forms 140
8.1 Dialogs 141
Standard dialogs 141, Data entry dialogs 142, Single-shot forms 146, Tkinter variables 152
8.2 A standard application framework 155 8.3 Data dictionaries 165 8.4 Notebooks 172 8.5 Browsers 175 8.6 Wizards 184 8.7 Image maps 191 8.8 Summary 198
9
Panels and machines 199
9.1 Building a front panel 199 9.2 Modularity 201
xii
CONTENTS9.3 Implementing the front panel 201 9.4 GIF, BMP and overlays 215
9.5 And now for a more complete example 220 9.6 Virtual machines using POV-Ray 232
And now for something completely different... #10 The Example 233
9.7 Summary 236
10
Drawing blobs and rubber lines 237
10.1 Drawing on a canvas 238
Moving canvas objects 243
10.2 A more complete drawing program 244 10.3 Scrolled canvases 251
10.4 Ruler-class tools 254
10.5 Stretching canvas objects 258 10.6 Some finishing touches 262 10.7 Speed drawing 271
10.8 Summary 275
11
Graphs and charts 276
11.1 Simple graphs 276 11.2 A graph widget 279
Adding bargraphs 286, Pie charts 289
11.3 3-D graphs 292 11.4 Strip charts 296 11.5 Summary 298
12
Navigation 300
12.1 Introduction: navigation models 300 12.2 Mouse navigation 301
12.3 Keyboard navigation: “mouseless navigation” 301 12.4 Building navigation into an application 302 12.5 Image maps 305
12.6 Summary 305
13
The window manager 306
13.1 What is a window manager? 306 13.2 Geometry methods 307
13.3 Visibility methods 308 13.4 Icon methods 309
C O N T EN T S
xiii
13.5 Protocol methods 309
13.6 Miscellaneous wm methods 310
Part 3 Putting it all together... 311
14
Extending Python 313
14.1 Writing a Python extension 313 14.2 Building Python extensions 316
Linking an extension statically in UNIX 316, Linking an extension
statically in Windows 317, Building a dynamic module in UNIX 317, Building a dynamic module in Windows 318, Installing dynamic modules 319, Using dynamic modules 319
14.3 Using the Python API in extensions 319 14.4 Building extensions in C++ 320 14.5 Format strings 321 14.6 Reference counts 324 14.7 Embedding Python 325 14.8 Summary 328
15
Debugging applications 329
15.1 Why print statements? 329 15.2 A simple example 330 15.3 How to debug 333 15.4 A Tkinter explorer 334 15.5 pdb 336 15.6 IDLE 336 15.7 DDD 337
16
Designing effective graphics applications 338
16.1 The elements of good interface design 339 16.2 Human factors 342
Choosing fonts 343, Use of color in graphical user interfaces 344, Size considerations 346
16.3 Alternative graphical user interfaces 346 16.4 Summary 347
17
Programming for performance 348
17.1 Everyday speedups 348
xiv
CONTENTS17.2 Tkinter performance 350
Keep it short! 350, Eliminate local variables 351, Keep it simple 351, Fast initialization 352, Throttling events 352
17.3 Python techniques 352
Importing modules 353, Concatenating strings 353, Getting nested loops right 354, Eliminate module references 354, Use local variables 355, Using exceptions 356, Using map, filter and reduce 356
17.4 Application profiling 357 17.5 Python extensions 359 17.6 Summary 360
18
Threads and asynchronous techniques 361
18.1 Threading 361
Non-GUI threads 362, GUI threads 365
18.2 “after” processing 369 18.3 Summary 373
19
Distributing Tkinter applications 374
19.1 General issues in distributing applications 374 19.2 Distributing UNIX applications 375
19.3 Distributing Win32 applications 376 19.4 Python distribution tools 379
Part 4 Appendices 381
appendix A Mapping Tk to Tkinter 383
appendix B Tkinter reference 425
appendix C Pmw reference: Python megawidgets 542
appendix D Building and installing Python, Tkinter 610
appendix E Events and keysyms 617
appendix F Cursors 621
appendix G References 625
index 629
xv
preface
I first encountered Python in 1993 when I joined a small company in Rhode Island. Their pri-mary product was a GUI-builder for X/Motif that generated code for C, C++, Ada and Python. I was tasked with extending the object-oriented interface for X/Motif and Python. In the past I’d become skeptical about the use of interpretive languages, so I began the task with little excite-ment. Two days later I was hooked. It was easy to develop interfaces that would have taken much more time and code to develop in C. Soon after, I began to choose interfaces developed using the Python interface in preference to compiled C code.
After I left the company in Rhode Island, I began to develop applications using Tkinter, which had become the preeminent GUI for Python. I persuaded one company, where I was working on contract, to use Python to build a code-generator to help complete a huge project that was in danger of overrunning time and budget. The project was a success. Four years later there are many Python programmers in that company and some projects now use Tkinter and Python for a considerable part of their code.
It was this experience, though, that led me to start writing this book. Very little documenta-tion was available for Tkinter in the early days. The Tkinter Life Preserver was the first document that helped people pull basic information together. In 1997 Fredrik Lundh released some excel-lent documentation for the widget classes on the web, and this has served Tkinter programmers well in the past couple of years. One of the problems that I saw was that although there were sev-eral example programs available (the Python distribution contains sevsev-eral), they were mostly brief in content and did not represent a framework for a full application written with Tkinter. Of course, it is easy to connect bits of code together to make it do more but when the underlying architecture relies on an interpreter it is easy to produce an inferior product, in terms of execu-tion speed, aesthetics, maintainability and extensibility.
So, one of the first questions that I was asked about writing Tkinter was “How do I make an XXX?” I’d usually hand the person a chunk of code that I’d written and, like most professional programmers, they would work out the details. I believe strongly that learning from full, working examples is an excellent way of learning how to program in a particular language and to achieve particular goals.
When I was training in karate, we frequently traveled to the world headquarters of Shuko-kai, in New Jersey, to train with the late Sensei Shigeru Kimura. Sensei Kimura often told us “I
xvi
PREFACE can’t teach you how to do this (a particular technique)—you have to steal it.” My approach to learning Tkinter is similar. If someone in the community has solved a problem, we need to steal it from them. Now, I am not suggesting that we infringe copyright and professional practice! I simply mean you should learn from whatever material is available. I hope that you will use the examples in the book as a starting point for your own creations. In a small number of cases I have used code or the ideas of other programmers. If this is the case I have given the original author an appropriate acknowledgment. If you use one of these pieces of code, I’d appreciate it if you would also acknowledge the original author. After all, what we “steal” has more value than what we pro-duce ourselves—it came from the Sensei!I was impressed by the format of Douglas A. Young’s The X Window System: Programming
and Applications with Xt. It is a little old now, but it had a high proportion of complete code
examples, some of which made excellent templates upon which new applications could be built.
Python and Tkinter Programming has some parallels in its layout. You will find much longer
examples than you may be accustomed to in other programming books. I hope that many of the examples will be useful either as templates or as a source of inspiration for programmers who have to solve a particular problem.
One side effect of presenting complete examples as opposed to providing code fragments is that you will learn a great deal about my style of programming. During the extensive reviews for
Python and Tkinter Programming some of the reviewers suggested alternate coding patterns for
some of the examples. Wherever possible, I incorporated their suggestions, so that the examples now contain the programming styles of several people. I expect that you will make similar improvements when you come to implement your own solutions.
I hope that you find Python and Tkinter Programming useful. If it saves you even a couple of hours when you have an application to write, then it will have been worth the time spent reading the book.
xvii
special thanks
Writing Python and Tkinter Programming has been the collective effort of many people. Each of these persons contributed their time, expertise and effort to help make the book more effective. Many of the words are theirs and not mine—the book is now better.
I want to thank the team of technical reviewers: Fred L. Drake, Robin Friedrich, Alan Gauld, Bob Gibson, Lynn Grande, Doug Hellmann, Garrett G. Hodgson, Paul Kendrew, Andrew M. Kuchling, Cameron Laird, Gregory A. Landrum, Ivan Van Laningham, Burt Leaven-worth, Ken McDonald, Frank McGeough, Robert Meegan, William Peloquin, Robert J. Roberts and Guido van Rossum. They provided detailed comments that resulted in significant improve-ments to the book’s content, focus and accuracy.
Some of the code examples were derived from code written by others. I want to thank these authors for agreeing to allow me to use their code in this book.
Doug Hellman wrote an excellent module for Pmw, GUIAppD.py, which I adapted as App-Shell.py and used for many examples within the book. Doug agreed that I could use the code. If you find AppShell.py useful in your applications, please acknowledge the original author of this work.
Konrad Hinsen wrote TkPlotCanvas.py, which was intended to be used with NumPy, which uses extension modules optimized for numerical operations. I adapted it to run without NumPy and also added some additional graphical capabilities. Again, if you find it useful, please acknowledge Konrad Hinsen.
The Tree and Node classes used in chapter 8 are derived from code released by OpenChem for inclusion within their Open Source project. You might want to look at any future releases from this organization, since the tree-widget examples presented in this book are limited in their capability.
Appendix B uses the man pages for Tk as a starting point for documenting Tkinter. The copyright owners, the Regents of the University of California and Sun Microsystems allow deriv-ative works to be made, provided that the original copyright is acknowledged.
I also want to thank Gordon Smith at General Dynamics for having confidence in the use of Python and Tkinter in some of the projects for which he was responsible; observing their use in real-world applications is one of the factors that prompted me to begin the task of writing the
xviii
S P EC IA L T H AN KS book. I was able to test some of the draft chapters by giving them to his staff and intern students to solve some of their programming tasks.Next, I want to thank everyone at Manning Publications who turned my ideas into a book. I had many long conversations with the publisher, Marjan Bace, who led me through the some-what complex task of writing a book that is going to be useful to its readers. Ted Kennedy coor-dinated the review process which produced much constructive criticism. Mary Piergies took care of the production of the book with Kristen Black, the copyeditor, and Dottie Marsico, the type-setter, who took my crude attempts to use FrameMaker and gave the book the professional edge it needed. Doug Hellman did a fine technical edit and corrected many code problems found in the final typeset copy.
Finally, I’d like to thank my wife, Allison, and my children, Nina, Chris, Jeff and Alana, for understanding that it wasn’t so much losing a spouse and father but gaining an author.
xix
about the reader
Python and Tkinter Programming is intended for programmers who already know Python or who
are learning Python (perhaps using Manning’s Quick Python as their guide) who wish to add graphical user interfaces (GUIs) to their applications. Because Python and Tkinter Programming presents many fully functional examples with lots of code annotations, experienced programmers
without Python expertise will find the book helpful in using Python and Tkinter to solve
imme-diate problems.
The book may also be used by Tcl/Tk script programmers as a guide to converting from Tcl/Tk to Python and Tkinter. However, I do not intend to get into a philosophical discussion about whether that would be a proper thing to do—I’m biased!
xx
about the author
John Grayson is a consultant specializing in graphical user interfaces (GUIs). He has been sup-porting application design at a large U.S. communications company for several years, designing innovative interfaces and introducing Python and Object-Oriented Programming (OOP) to tra-ditional development methods. Elsewhere, he has delivered real-world applications written in Python and Tkinter for commercial use.
He holds a Bachelor's degree in Applied Biology and a Ph.D. in Molecular Biology—but that has never been an impediment (especially because 90 percent of his thesis covered computer modeling of enzyme behavior).
Before specializing in user interfaces, he was an operating-system specialist and was later instrumental in developing support methodologies for UNIX at Stratus Computer, Inc., he built an F77 compiler and UNIX porting tools at Pacer Software, Inc. and he was an operating-system specialist at Prime Computer, Inc. both in the United States and Great Britain.
xxi
conventions
Example code plays a very important role in Python and Tkinter Programming. Many program-ming books feature short, simple examples which illustrate one or two points very well—but really do little. In this book, the examples may be adapted for your own applications or even used just as they are. Most of the examples are intended to be run stand-alone as opposed to being run
interactively. Most examples include markers in the body of the code which correspond to
expla-nations which follow. For example:
def mouseDown(self, event): self.currentObject = None
self.lastx = self.startx = self.canvas.canvasx(event.x) self.lasty = self.starty = self.canvas.canvasy(event.y) if not self.currentFunc: self.selObj = self.canvas.find_closest(self.startx, self.starty)[0] self.canvas.itemconfig(self.selObj, width=2) self.canvas.lift(self.selObj) Code comments
The mouseDown method deselects any currently selected object. The event returns x and y
coordi-nates for the mouse-click as screen coordicoordi-nates. The canvasx and canvasy methods of the
Canvas widget ...
If no drawing function is selected, we are in select mode and we search to locate the nearest object on the canvas and select it. This method of ...
Occasionally, I have set portions of code in bold code font to highlight code which is of special importance in the code example.
In a number of examples where the code spans several pages I have interspersed code expla-nations within the code sequence so that the explanatory text appears closer to the code that is being explained. The marker numbering is continuous within any given example.
1
2
1 2
xxii
about the cover
The cover illustration of this book is from the 1805 edition of Sylvain Maréchal’s four-volume compendium of regional dress customs. This book was first published in Paris in 1788, one year before the French Revolution. Its title alone required no fewer than 30 words:
Costumes Civils actuels de tous les peuples connus dessinés d’après nature gravés et coloriés, accompagnés d’une notice historique sur leurs coutumes, moeurs, religions, etc., etc., redigés par M. Sylvain Maréchal
The four volumes include an annotation on the illustrations: “gravé à la manière noire par Mixelle d’après Desrais et colorié.” Clearly, the engraver and illustrator deserved no more than to be listed by their last names—after all they were mere technicians. The workers who colored each illustration by hand remain nameless.
The colorful variety of this collection reminds us vividly of how culturally apart the world’s towns and regions were just 200 years ago. Dress codes have changed everywhere and the diver-sity by region, so rich at the time, has faded away. It is now hard to tell the inhabitant of one con-tinent from another. Perhaps we have traded cultural diversity for a more varied personal life— certainly a more varied and exciting technological environment. At a time when it is hard to tell one computer book from another, Manning celebrates the inventiveness and initiative of the computer business with book covers based on the rich diversity of regional life of two centuries ago, brought back to life by Maréchal’s pictures. Just think, Maréchal’s was a world so different from ours people would take the time to read a book title 30 words long.
xxiii
author online
Purchase of Python and Tkinter Programming includes free access to a private Internet forum where you can make comments about the book, ask technical questions and receive help from the author and other Python and Tkinter users. To access the forum, point your web browser to www.manning.com/grayson. There you will be able to subscribe to the forum. This site also pro-vides information on how to access the forum once you are registered, what kind of help is avail-able and the rules of conduct on the forum.
All source code for the examples presented in this book is available from the Mannng web-site. The URL www.manning.com/grayson includes a link to the source code files.
1
P A
R
T
Basic concepts
I
n part 1, I’ll introduce Python, Tkinter and application programming. Since I assume you’re already somewhat familiar with Python, chapter 1 is intended to illustrate the most important features of the language that will be used throughout the book. Additionally, I’ll discuss features of Python’s support for object-oriented programming so that those of you familiar with C++ or Java can under-stand how your experience may be applied to Python.Chapter 2 quickly introduces Tkinter and explains how it relates to Tcl/Tk. You will find details of mapping Tk to Tkinter, along with a brief introduction to the widgets and their appearance.
Chapter 3 illustrates application development with Tkinter using two calculator examples. The first is a simple no-frills calculator that demonstrates basic principles. The second is a partially finished application that shows you how powerful applications may be developed using Python’s and Tkinter’s capabilities.
3
C
H
A
P
T
E
R
1
Python
1.1 Introduction to Python programming and a feature review 3 1.2 Key data types: lists, tuples and dictionaries 5
1.3 Classes 9
This chapter defines the key features of Python that make the language ideal for rapid proto-typing of systems and for fully-functional applications. Python and Tkinter Programming is not intended to be a learning resource for beginning Python programmers; several other publications are better-suited to this task: Quick Python, Learning Python, Programming
Python, Internet Programming in Python and The Python Pocket Reference are all excellent
texts. Further information is provided in the “References” section at the end of this book. In this chapter, the key features of Python will be highlighted in concise examples of code to illustrate some of the building blocks that will be used in examples throughout the book.
1.1 Introduction to Python programming and
a feature review
As stated earlier, this book is not intended to be used to learn Python basics directly. Pro-grammers experienced in other languages will be able to analyze the examples and discover the key points to programming in Python. However, if you are relatively new to program-ming generally, then learning Python this way will be a tough, upward struggle.
4
CHAPTER 1 PYTHON This chapter is really not necessary for most readers, then, since the material will already be familiar. Its purpose is to provide a refresher course for readers who worked with Python in the early days and a map for Tcl/Tk programmers and those readers experienced with other languages.Readers unfamiliar with object-oriented programming (OOP) may find section 1.3 use-ful as an introduction to OOP as it is implemented in Python. C++ or Java programmers who need to see how Python’s classes operate will benefit as well.
I’m not going to explain the reasons why Python was developed or when, since this infor-mation is covered in every other Python book very well. I will state that Guido van Rossum, Python’s creator, has been behind the language since he invented it at Stichting Mathematisch Centrum (CWI) in Amsterdam, The Nederlands, around 1990; he is now at the Corporation for National Research Initiatives (CNRI), Reston, Virginia, USA. The fact that one person has taken control of the growth of the language has had a great deal to do with its stability and elegance, although Guido will be the first to thank all of the people who have contributed, in one way or another, to the language’s development.
Perhaps more important than any of the above information is the name of the language. This language has nothing to do with snakes. Python is named after Monty Python’s Flying
Cir-cus, the BBC comedy series which was produced from 1969 to 1974. Like many university
stu-dents around 1970, I was influenced by Monty Python, so when I started writing this book I could not resist the temptation to add bits of Python other than the language. Now, all of you that skipped the boring beginning bit of this book, or decided that you didn’t need to read this paragraph are in for a surprise. Scattered through the examples you’ll find bits of Python. If you have never experienced Monty Python, then I can only offer the following advice: if some-thing about the example looks weird, it’s probably Python. As my Yugoslavian college friend used to say “You find that funny”?
1.1.1
Why Python?
Several key features make Python an ideal language for a wide range of applications. Adding Tkinter to the mix widens the possibilities dramatically. Here are some of the highlights that make Python what it is:
• Automatic compile to bytecode • High-level data types and operations • Portability across architectures
• Wide (huge) range of supported extensions • Object-oriented model
• Ideal prototyping system
• Readable code with a distinct C-like quality supports maintenance • Easy to extend in C and C++ and embed in applications
• Large library of contributed applications and tools • Excellent documentation
You might notice that I did not mention an interpreter explicitly. One feature of Python is that it is a bytecode engine written in C. The extension modules are written in C. With a little care in the way you design your code, most of your code will run using compiled C since many operations are built into the system. The remaining code will run in the bytecode engine.
KE Y D A T A TY P ES : L I ST S , T U PL E S A N D D I C T I O N A R I E S
5
The result is a system that may be used as a scripting language to develop anything from some system administration scripts all the way to a complex GUI-based application (using database, client/server, CORBA or other techniques).1.1.2
Where can Python be used?
Knowing where Python can be used is best understood by learning where it might not be the best choice. Regardless of what I just said about the bytecode engine, Python has an interpre-tive nature, so if you can’t keep within the C-extensions, there has to be a performance pen-alty. Therefore, real-time applications for high-speed events would be a poor match. A set of extensions to Python have been developed specifically for numerical programming (see “NumPy” on page 626). These extensions help support compute-bound applications, but Python is not the best choice for huge computation-intensive applications unless time isn’t a factor. Similarly, graphics-intensive applications which involve real-time observation are not a good match (but see “Speed drawing” on page 271 for an example of what can be done).
1.2 Key data types: lists, tuples and dictionaries
Three key data types give Python the power to produce effective applications: two sequence classes—lists and tuples—and a mapping class—dictionaries. When they are used together, they can deliver surprising power in a few lines of code.
Lists and tuples have a lot in common. The major difference is that the elements of a list
can be modified in place but a tuple is immutable: you have to deconstruct and then reconstruct a tuple to change individual elements. There are several good reasons why we should care about this distinction; if you want to use a tuple as the key to a dictionary, it’s good to know that it can’t be changed arbitrarily. A small advantage of tuples is that they are a slightly cheaper resource since they do not carry the additional operations of a list.
If you want an in-depth view of these data types take a look at chapters 6 and 8 of Quick Python.
1.2.1
Lists
Let’s look at lists first. If you are new to Python, remember to look at the tutorial that is avail-able in the standard documentation, which is availavail-able at www.python.org.
Initializing lists
Lists are easy to create and use. To initialize a list:
lst = [] # Empty list
lst = ['a', 'b', 'c'] # String list
lst = [1, 2, 3, 4] # Integer list
lst = [[1,2,3], ['a','b','c']] # List of lists
lst = [(1,'a'),(2,'b'),(3,'c')] # List of tuples
Appending to lists
Lists have an append method built in:
lst.append('e') lst.append((5,'e'))
6
CHAPTER 1 PYTHONConcatenating lists
Combining lists works well:
lst = [1, 2, 3] + [4, 5, 6] print lst
[1, 2, 3, 4, 5, 6]
Iterating through members
Iterating through a list is easy:
lst = ['first', 'second', 'third'] for str in lst:
print 'this entry is %s' % str
set = [(1, 'uno'), (2, 'due'), (3, 'tres')] for integer, str in set:
print 'Numero "%d" in Italiano: è "%s"' % (integer, str)
Sorting and reversing
Lists have built-in sort and reverse methods:
lst = [4, 5, 1, 9, 2] lst.sort() print lst [1, 2, 4, 5, 9] lst.reverse() print lst [9, 5, 4, 2, 1] Indexing
Finding an entry in a list:
lst = [1, 2, 4, 5, 9] print lst.index(5)
3
Member
Checking membership of a list is convenient:
if 'jeg' in ['abc', 'tuv', 'kie', 'jeg']: ...
if '*' in '123*abc': ...
Modifying members
A list member may be modified in place:
lst = [1, 2, 4, 5, 9] lst[3] = 10
print lst
KE Y D A T A TY P ES : L I ST S , T U PL E S A N D D I C T I O N A R I E S
7
Inserting and deleting members
To insert a member in a list:
lst = [1, 2, 3, 4, 10, 9] lst.insert(4, 5) print lst [1, 2, 3, 4, 5, 10, 9] To delete a member: lst = [1, 2, 3, 4, 10, 9] del lst(4) print lst [1, 2, 3, 4, 9]
1.2.2
Tuples
Tuples are similar to lists but they are immutable (meaning they cannot be modified). Tuples are a convenient way of collecting data that may be passed as a single entity or stored in a list or dictionary; the entity is then unpacked when needed.
Initializing tuples
With the exception of a tuple containing one element, tuples are initialized in a similar man-ner to lists (lists and tuples are really related sequence types and are readily interchangeable).
tpl = () # Empty tuple
tpl = (1,) # Singleton tuple
tpl = ('a', 'b', 'c') # String tuple
tpl = (1, 2, 3, 4) # Integer tuple
tpl = ([1,2,3], ['a','b','c']) # Tuple of lists
tpl = ((1,'a'),(2,'b'),(3,'c')) # Tuple of tuples
Iterating through members
for i in tpl: ...
for i,a in ((1, 'a'), (2, 'b'), (3, 'c')): ...
Modifying tuples
(But you said tuples were immutable!)
a = 1, 2, 3
a = a[0], a[1], 10, a[2] a
(1, 2, 10, 3)
Note that you are not modifying the original tuple but you are creating a new name bind-ing for a.
8
CHAPTER 1 PYTHON1.2.3
Dictionaries
Dictionaries are arrays of data indexed by keys. I think that they give Python the edge in
designing compact systems. If you use lists and tuples as data contained within dictionaries you have a powerful mix (not to say that mixing code objects, dictionaries and abstract objects isn’t powerful!).
Initializing dictionaries
Dictionaries may be initialized by providing key:value pairs:
dict = {} # Empty dictionary
dict = {'a'': 1, 'b': 2, 'c': 3} # String key
dict = {1: 'a', 2: 'b', 3: 'c'} # Integer key
dict = {1: [1,2,3], 2: [4,5,6]} # List data
Modifying dictionaries
Dictionaries are readily modifiable:
dict['a'] = 10 dict[10] = 'Larch'
Accessing dictionaries
Recent versions of Python facilitate lookups where the key may not exist. First, the old way:
if dict.has_key('a'): value = dict['a'] else: value = None or: try: value = dict['a'] except KeyError: value = None
This is the current method:
value = dict.get('a', None)
Iterating through entries
Get the keys and then iterate through them:
keys = dict.keys() for key in keys:
...
Sorting dictionaries
Dictionaries have arbitrary order so you must sort the keys if you want to access the keys in order:
keys = dict.keys().sort() for key in keys:
C LA S S E S
9
1.3 Classes
I’m including a short section on Python classes largely for C++ programmers who may need to learn some of the details of Python’s implementation and for Python programmers who have yet to discover OOP in Python.
1.3.1
How do classes describe objects?
A class provides the following object descriptions: • The attributes (data-members) of the object • The behavior of the object (methods)
• Where behavior is inherited from other classes (superclasses)
Having said all that, C++ programmers will probably be tuning out at this point—but hold on for a little longer. There are some valuable features of Python classes, some of which may come as a bit of a surprise for someone who is not fully up to speed with Python OOP.
Most of the examples of applications in this book rely heavily on building class libraries to create a wide range of objects. The classes typically create instances with multiple formats (see LEDs and Switches in chapter 7). Before we start building these objects, let’s review the rules and features that apply to Python classes.
1.3.2
Defining classes
A Python class is a user-defined data type which is defined with a class statement:
class AClass: statements
Statements are any valid Python statements defining attributes and member functions. In
fact, any Python statement can be used, including a pass statement, as we will see in the next
section. Calling the class as a function creates an instance of the class:
anInstanceOfAClass = AClass()
1.3.3
Neat Python trick #10
A class instance can be used like a C structure or Pascal record. However, unlike C and Pascal, the members of the structure do not need to be declared before they are used—they can be created dynamically. We can use this ability to access arbitrary data objects across modules; examples using class instances to support global data will be shown later.
class DummyClass: pass Colors = DummyClass() Colors.alarm = 'red' Colors.warning = 'orange' Colors.normal = 'green'
If the preceding lines are stored in a file called programdata.py, the following is a possible code sequence.
10
CHAPTER 1 PYTHONfrom programdata import Colors ...
Button(parent, bg=Colors.alarm, text='Pressure\nVessel',
command=evacuateBuilding)
Alternately, if you apply a little knowledge about how Python manages data internally, you can use the following construction.
class Record:
def __init__(self, **kw): self.__dict__.update(kw)
Colors = Record(alarm='red', warning='orange', normal='green')
1.3.4
Initializing an instance
Fields (instance variables) of an instance may be initialized by including an __init__
method in the class body. This method is executed automatically when a new instance of the class is created. Python passes the instance as the first argument. It is a convention to name it
self (it’s called this in C++). In addition, methods may be called to complete initialization.
The __init__ methods of inherited classes may also be called, when necessary.
class ASX200(Frame):
def __init__(self, master=None): Frame.__init__(self, master) Pack.config(self) self.state = NORMAL self.set_hardware_data(FORE) self.createWidgets() ... ... switch = ASX200() I
To use instance variables you must reference the containing object (in the previ-ous example it is switch.state, not self.state). If you make a reference to
a variable by itself, it is to a local variable within the executing function, not an instance variable.
1.3.5
Methods
We have already encountered the __init__ method that is invoked when an instance is
cre-ated. Other methods are defined similarly with def statements. Methods may take
argu-ments: self is always the first or only argument.
You will see plenty of examples of methods, so little discussion is really necessary. Note that Python accepts named arguments, in addition to positional arguments, in both methods and function calls. This can make supplying default values for methods very easy, since omis-sion of an argument will result in the default value being supplied. Take care when mixing posi-tional and named arguments as it is very easy to introduce problems in class libraries this way.
C LA S S E S
11
1.3.6
Private and public variables and methods
Unless you take special action, all variables and methods are public and virtual. If you make use of name mangling, however, you can emulate private variables and methods. You mangle the name this way: Any name which begins with a double-underscore (__) is private and is not exported to a containing environment. Any name which begins with a single underscore (_) indicates private by convention, which is similar to protected in C++ or Java. In fact, Python usually is more intuitive than C++ or other languages, since it is immediately obvious if a ref-erence is being made to a private variable or method.
1.3.7
Inheritance
The rules of inheritance in Python are really quite simple:
• Classes inherit behavior from the classes specified in their header and from any classes above these classes.
• Instances inherit behavior from the class from which they are created and from all the classes above this class.
When Python searches for a reference it searches in the immediate namespace (the instance) and then in each of the higher namespaces. The first occurrence of the reference is used; this means that a class can easily redefine attributes and methods of its superclasses. If the reference cannot be found Python reports an error.
Note that inherited methods are not automatically called. To initialize the base class, a subclass must call the __init__ method explicitly.
1.3.8
Multiple inheritance
Multiple inheritance in Python is just an extension of inheritance. If more than one class is specified in a class’s header then we have multiple inheritance. Unlike C++, however, Python does not report errors if attributes of classes are multiple defined; the basic rule is that the first occurrence found is the one that is used.
1.3.9
Mixin classes
A class that collects a number of common methods and can be freely inherited by subclasses is usually referred to as a mixin class (some standard texts may use base, generalized or abstract classes, but that may not be totally correct). Such methods could be contained in a Python module, but the advantage of employing a mixin class is that the methods have access to the instance self and thus can modify the behavior of an instance. We will see examples of mixin
12
C
H
A
P
T
E
R
2
Tkinter
2.1 The Tkinter module 12 2.2 Mapping Tcl/Tk to Tkinter 14 2.3 Win32 and Unix GUIs 15
2.4 Tkinter class hierarchy 16 2.5 Tkinter widget appearance 17
This chapter describes the structure of the Tkinter module and its relationship to Tcl/Tk. The mapping with Tcl/Tk constructs to Tkinter is explained in order to assist Tcl/Tk pro-grammers in converting to Tkinter from Tcl/Tk. Native GUIs for UNIX, Win32 and Mac-intosh implementations will be discussed and key architectural differences will be highlighted. Font and color selection will be introduced, and I’ll cover this topic in more detail in “Tkinter widgets” on page 31. For readers who are unfamiliar with Tkinter, this chapter illustrates its importance to Python applications.
2.1
The Tkinter module
2.1.1
What is Tkinter?
Tkinter provides Python applications with an easy-to-program user interface. Tkinter sup-ports a collection of Tk widgets that support most application needs. Tkinter is the Python interface to Tk, the GUI toolkit for Tcl/Tk. Tcl/Tk is the scripting and graphics facility developed by John Ousterhout, who was originally at University of California at Berkeley
T H E T K I N T E R M O D U L E
13
and later at Sun Microsystems. Currently, Tcl/Tk is developed and supported by the Scriptics Corporation, which Ousterhout founded. Tcl/Tk enjoys a significant following with develop-ers in a number of fields, predominantly on UNIX systems, but more recently on Win32 sys-tems and MacOS. Ousterhout’s Tcl and the Tk Toolkit, which was the first Tcl/Tk book, is still a viable, though old, reference document for Tcl/Tk. (You will find some excellent newer texts on the subject in the section “References” on page 625 ).Tcl/Tk was first designed to run under the X Window system and its widgets and win-dows were made to resemble Motif widgets. The behavior of bindings and controls was also designed to mimic Motif. In recent versions of Tcl/Tk (specifically, release 8.0 and after), the widgets resemble native widgets on the implemented architecture. In fact, many of the widgets
are native widgets and the trend to add more of them will probably continue.
Like Python extensions, Tcl/Tk is implemented as a C library package with modules to support interpreted scripts, or applications. The Tkinter interface is implemented as a Python module, Tkinter.py, which is bound to a C-extension (_tkinter) which utilizes these same
Tcl/Tk libraries. In many cases a Tkinter programmer need not be concerned with the imple-mentation of Tcl/Tk since Tkinter can be viewed as a simple extension of Python.
2.1.2
What about performance?
At first glance, it is reasonable to assume that Tkinter is not going to perform well. After all, the Python interpreter is utilizing the Tkinter module which, in turn, relies on the _tkinter
interface which calls Tcl and Tk libraries and sometimes calls the Tcl interpreter to bind properties to widgets. Well, this is all true, but on modern systems it really does not matter too much. If you follow the guidelines in “Programming for performance” on page 348, you will find that Python and Tkinter have the ability to deliver viable applications. If your reason for using Python/Tkinter is to develop prototypes for applications, then the point is some-what moot; you will develop prototypes quickly in Python/Tkinter.
2.1.3
How do I use Tkinter?
Tkinter comprises a number of components. _tkinter, as mentioned before, is the low level
interface to the Tk libraries and is linked into Python. Until recently, it was the programmer’s responsibility to add Tkinter to the Python build, but beginning with release 1.5.2 of Python, Tkinter, Tcl and Tk are part of the installation package—at least for the Win32 distribution. For several UNIX variants and Macintosh, it is still necessary to build Python to include Tkinter. However, check to see if a binary version is available for your particular platform.
Once a version of Python has been built and _tkinter has been included, as a shared
library, dll or statically linked, the Tkinter module needs to be imported. This imports any other necessary modules, such as Tkconstants.
To create a Tkinter window, type three lines into the Python com-mand line (or enter them into a file and type “python filename.py”).
Figure 2.1 Trivial Example
14
CHAPTER 2 TKINT ERfrom Tkinter import Label, mainloop
Label(text=’This has to be the\nsimplest bit of code’).pack() mainloop()
Code comments
First, we import components from the Tkinter module. By using from module import
Label, mainloop we avoid having to reference the module to access attributes and methods
contained in the module.
We create a Label containing two lines of text and use the Pack geometry manager to realize
the widget.
Finally, we call the Tkinter mainloop to process events and keep the display activated. This
example does not react to any application-specific events, but we still need a mainloop for it to be displayed; basic window management is automatic.
What you will see is shown in figure 2.1. Now, it really cannot get much simpler than that!
2.1.4
Tkinter features
Tkinter adds object-oriented interfaces to Tk. Tcl/Tk is a command-oriented scripting lan-guage so the normal method of driving Tk widgets is to apply an operation to a widget identi-fier. In Tkinter, the widget references are objects and we drive the widgets by using object
methods and their attributes. As a result, Tkinter programs are easy to read and understand,
especially for C++ or Java programmers (although that is entirely another story!).
One important feature that Tk gives to any Tkinter application is that, with a little care in selecting fonts and other architecture-dependent features, it will run on numerous flavors of UNIX, Win32 and Macintosh without modification. Naturally, there are some intrinsic dif-ferences between these architectures, but Tkinter does a fine job of providing an architecture-independent graphics platform for applications.
It is the object-oriented features, however, that really distinguish Tkinter as an ideal plat-form for developing application frameworks. You will see many examples in this book where relatively little code will support powerful applications.
2.2 Mapping Tcl/Tk to Tkinter
Mapping of Tcl/Tk commands and arguments to Tkinter is really quite a simple process. After writing Tkinter code for a short time, it should be easy for a Tcl/Tk programmer to make the shift—maybe he will never go back to Tcl/Tk! Let’s look at some examples.
Commands in Tk map directly to class constructors in Tkinter.
1 2 3 1 2 3 Txl/Tk Tkinter
W I N 3 2 A N D U N I X G U I S
15
Parent widgets (usually referred to as master widgets) are explicit in Tkinter:For configuration options, Tk uses keyword arguments followed by values or configure commands; Tkinter uses either keyword arguments or a dictionary reference to the option of the configure method in the target widget.
Since the Tkinter widget object has methods, you invoke them directly, adding argu-ments as appropriate.
The following illustration demonstrates how we access an inherited method pack from the Packer. This style of programming contributes to the compactnature of Tkinter applications and their ease of maintenance and reuse.
Full mappings of Tk to Tkinter are provided in “Mapping Tk to Tkinter” on page 383.
2.3 Win32 and U
NIX
GUIs
As I mentioned earlier, it is reasonable to develop Tkinter applications for use in Win32, UNIX and Macintosh environments. Tcl/Tk is portable and can be built on the specific plat-form, as can Python, with its _tkinter C module. Using Pmw* (Python MegaWidgets),
which provides a portable set of composite widgets and is 100% Python code, it is possible to use the bytecode generated on a UNIX system on a Win32 or Macintosh system. What you cannot control is the use of fonts and, to a lesser extent, the color schemes imposed by the operating system.
Tcl/Tk Tkinter
label .screen.for label = Label(form) (screen is form’s parent)
Tcl/Tk Tkinter
label .myLabel -bg blue myLabel = Label(master, bg=“blue”) .myLabel configure -bg blue myLabel[“bg”] = “blue”
myLabel.configure(bg = “blue”)
Tcl/Tk Tkinter
pack label -side left -fill y label.pack(side=LEFT, fill=Y)
* Pmw—Python MegaWidgets provide complex widgets, constructed from fundamental Tkinter wid-gets, which extend the available widgets to comboboxes, scrolled frames and button boxes, to name a few. Using these widgets gives GUI developers a rich palette of available input devices to use in their designs.
16
CHAPTER 2 TKINT ER Take a look at figure 2.2. This application uses Pmw combobox widgetsalong with Tkinter button and entry
widgets arranged within frames. The
font for this example is Arial, bold and 16 point. Apart from the obvious Win32 controls in the border, there is little to distinguish this window from the one shown in figure 2.3, which was run on UNIX. In this case, the font is Helvetica, bold and 16 point. The window is slightly larger because the font has slightly different kerning rules and stroke weight, and since the size of the widget is dependent on the font, this results in a slightly different layout. If precise align-ment and sizing is an absolute require-ment, it is possible to detect the platform on which the application is running and make adjustments for known differ-ences. In general, it is better to design an application that is not sensitive to small changes in layout.
If you look closely, you may also notice a difference in the top and bottom highlights for the Execute and Close but-tons, but not for the buttons on the Pmw widgets. This is because Tk is drawing Motif decorations for UNIX and Win-dows SDK decorations for Win32.
In general, as long as your applica-tion does not make use of very platform-specific fonts, it will be possible to develop transportable code.
2.4 Tkinter class hierarchy
Unlike many windowing systems, the Tkinter hierarchy is really quite simple; in fact, there really isn’t a hierarchy at all. The WM, Misc, Pack, Place and Grid classes are mixins to each of the widget classes. Most programmers only need to know about the lowest level in the tree to perform everyday operations and it is often possible to ignore the higher levels. The notional “hierarchy” is shown in figure 2.4.
Figure 2.2 Tkinter and Pmw on win32
T K I N T E R W I D G ET A P P EA R A N CE
17
2.5 Tkinter
widget
appearance
To conclude this initial introduction to Tkinter, let’s take a quick look at the appearance of the widgets avail-able to a programmer. In this exam-ple, we are just looking at the basic configuration of the widgets and only one canvas drawing option is shown. I’ve changed the border on the frames to add some variety, but you are see-ing the widgets with their default appearance. The widgets are shown in figure 2.5. The code is not presented here, but it is available online.
Figure 2.4 Tkinter widget “hierarchy”
Frame Label Button Entry CheckButton Menu MenuButton Message Text Canvas Scale Scrollbar RadioButton Listbox Wm Misc Grid Place Pack Tk Widget Toplevel Basewidget Mixin Inheritance
18
C
H
A
P
T
E
R
3
Building an application
3.1 Calculator example: key features 21 3.2 Calculator example: source code 21 3.3 Examining the application structure 27 3.4 Extending the application 28
Most books on programming languages have followed Kernigan and Ritchie’s example and have presented the obligatory “Hello World” example to illustrate the ease with which that language may be applied. Books with a GUI component seem to continue this tradition and present a “Hello GUI World” or something similar. Indeed, the three-line example presented on page 13 is in that class of examples.
There is a growing trend to present a calculator example in recent publications. In this book I am going to start by present-ing a simple calculator (you may add the word obligatory, if you wish) in the style of its predecessors. The example has been writ-ten to illustrate several Python and Tkinter features and to dem-onstrate the compact nature of Python code.
The example is not complete because it accepts only mouse input; in a full example, we would expect keyboard input as well. However, it does work and it demonstrates that you do not need a lot of code to get a Tkinter screen up and running. Let’s take a look at the code that supports the screen:
Figure 3.1 A simple calculator
19
from Tkinter import *
def frame(root, side): w = Frame(root)
w.pack(side=side, expand=YES, fill=BOTH) return w
def button(root, side, text, command=None): w = Button(root, text=text, command=command) w.pack(side=side, expand=YES, fill=BOTH) return w class Calculator(Frame): def __init__(self): Frame.__init__(self) self.pack(expand=YES, fill=BOTH) self.master.title('Simple Calculator') self.master.iconname("calc1") display = StringVar() Entry(self, relief=SUNKEN, textvariable=display).pack(side=TOP, expand=YES, fill=BOTH) for key in ("123", "456", "789", "-0."): keyF = frame(self, TOP)
for char in key:
button(keyF, LEFT, char,
lambda w=display, s=' %s '%char: w.set(w.get()+s))
opsF = frame(self, TOP) for char in "+-*/=":
if char == '=':
btn = button(opsF, LEFT, char) btn.bind('<ButtonRelease-1>',
lambda e, s=self, w=display: s.calc(w), '+') else:
btn = button(opsF, LEFT, char,
lambda w=display, c=char: w.set(w.get()+' '+c+' '))
clearF = frame(self, BOTTOM)
button(clearF, LEFT, 'Clr', lambda w=display: w.set(''))
def calc(self, display): try: display.set(`eval(display.get())`) except ValueError: display.set("ERROR") if __name__ == '__main__': Calculator().mainloop() calc1.py 1 2 3 4 5 6 7
20
CHAPTER 3 BUILDING AN APPLICATIO NCode comments
We begin by defining convenience functions to make the creation of frame and button wid-gets more compact. These functions use the pack geometry manager and use generally useful
values for widget behavior. It is always a good idea to collect common code in compact func-tions (or classes, as appropriate) since this makes readability and maintenance much easier. We call the Frame constructor to create the toplevel shell and an enclosing frame. Then, we
set titles for the window and icon.
Next, we create the display at the top of the calculator and define a Tkinter variable which provides access to the widget’s contents:
display = StringVar()
Entry(self.master, relief=SUNKEN,
textvariable=variable).pack(side=TOP, expand=YES, fill=BOTH)
Remember that character strings are sequences of characters in Python, so that each of the subsequences is really an array of characters over which we can iterate:
for key in ("123", "456", "789", "-0."): keyF = frame(self, TOP)
for char in key:
We create a frame for each row of keys.
We use the convenience function to create a button, passing the frame, pack option, label
and callback:
button(keyF, LEFT, char,
lambda w=display, c=char: w.set(w.get() + c))
Don’t worry about the lambda form of the callback yet, I will cover this in more detail
later. Its purpose is to define an inline function definition.
The = key has an alternate binding to the other buttons since it calls the calc method when
the left mouse button is released:
btn.bind('<ButtonRelease-1>',
lambda e, s=self, w=display: s.calc(w))
The calc method attempts to evaluate the string contained in the display and then it replaces
the contents with the calculated value or an ERROR message:
display.set(`eval(display.get())`)
Personally, I don’t like the calculator, even though it demonstrates compact code and will be quite easy to extend to provide more complete functionality. Perhaps it is the artist in me, but it doesn’t look like a calculator!
Let’s take a look at a partly-finished example application which implements a quite sophisticated calculator. It has been left unfinished so that curious readers can experiment by adding functionality to the example (by the time you have finished reading this book, you will be ready to build a Cray Calculator!). Even though the calculator is unfinished, it can still be put to some use. As we will discover a little later, some surprising features are hidden in the reasonably short source code.
Let’s start by taking a look at some of the key features of the calculator. 1 2 3 4 5 6 7
C A L CU L A T O R E X A MP L E : S O U R C E C O DE
21
3.1 Calculator example: key features
The calculator example illustrates many features of applications written in Python and Tkinter, including these:
• GUI application structure Although this is a simple example, it contains many of the elements of larger applications that will be presented later in the book. • Multiple inheritance It is simple in this example, but it
illustrates how it may be used to simplify Python code. • Lists, dictionaries and tuples As mentioned in
chapter 1, these language facilities give Python a con-siderable edge in building concise code. In particular, this example illustrates the use of a dictionary to dis-patch actions to methods. Of particular note is the use of lists of tuples to define the content of each of the keys. Unpacking this data generates each of the keys, labels and associated bindings in a compact fashion. • Pmw (Python megawidgets) The scrolled text widget is
implemented with Pmw. This example illustrates set-ting its attributes and gaining access to its components. • Basic Tkinter operations Creating widgets, setting
attributes, using text tags, binding events and using a geometry manager are demonstrated.
• eval and exec functions The example uses eval to
perform many of the math functions in this example. However, as you will see later in this chapter, eval
can-not be used to execute arbitrary Python code; exec is
used to execute single or multiple lines of code (and multiple lines of code can include control flow structures).
3.2 Calculator example: source code
from Tkinter import * import Pmw
class SLabel(Frame):
""" SLabel defines a 2-sided label within a Frame. The
left hand label has blue letters; the right has white letters. """ def __init__(self, master, leftl, rightl):
Frame.__init__(self, master, bg='gray40') self.pack(side=LEFT, expand=YES, fill=BOTH) Label(self, text=leftl, fg='steelblue1',
font=("arial", 6, "bold"), width=5, bg='gray40').pack( side=LEFT, expand=YES, fill=BOTH)
Label(self, text=rightl, fg='white',
font=("arial", 6, "bold"), width=1, bg='gray40').pack(
calc2.py
1 Python MegaWidgets
Figure 3.2 A better calculator
22
CHAPTER 3 BUILDING AN APPLICATIO Nside=RIGHT, expand=YES, fill=BOTH)
class Key(Button):
def __init__(self, master, font=('arial', 8, 'bold'), fg='white',width=5, borderwidth=5, **kw): kw['font'] = font
kw['fg'] = fg kw['width'] = width
kw['borderwidth'] = borderwidth
apply(Button.__init__, (self, master), kw) self.pack(side=LEFT, expand=NO, fill=NONE)
class Calculator(Frame):
def __init__(self, parent=None): Frame.__init__(self, bg='gray40') self.pack(expand=YES, fill=BOTH)
self.master.title('Tkinter Toolkit TT-42') self.master.iconname('Tk-42')
self.calc = Evaluator() # This is our evaluator
self.buildCalculator() # Build the widgets
# This is an incomplete dictionary - a good exercise!
self.actionDict = {'second': self.doThis, 'mode': self.doThis, 'delete': self.doThis, 'alpha': self.doThis, 'stat': self.doThis, 'math': self.doThis, 'matrix': self.doThis, 'program': self.doThis, 'vars': self.doThis, 'clear': self.clearall, 'sin': self.doThis, 'cos': self.doThis, 'tan': self.doThis, 'up': self.doThis, 'X1': self.doThis, 'X2': self.doThis, 'log': self.doThis, 'ln': self.doThis, 'store': self.doThis, 'off': self.turnoff 'neg': self.doThis, 'enter': self.doEnter,
} self.current = ""
def doThis(self,action):
print '"%s" has not been implemented' % action
def turnoff(self, *args): self.quit()
def clearall(self, *args): self.current = ""
self.display.component('text').delete(1.0, END)
def doEnter(self, *args):
self.display.insert(END, '\n')
result = self.calc.runpython(self.current) if result:
self.display.insert(END, '%s\n' % result, 'ans') self.current = ""
def doKeypress(self, event): key = event.char if key != '\b':
self.current = self.current + key
3 2 7 8 6 5 4