Section 10.9. The PyDemos and PyGadgets Launchers


10.9. The PyDemos and PyGadgets Launchers

To close out this chapter, let's explore the implementations of the two GUIs used to run major book examples. The following GUIs, PyDemos and PyGadgets, are simply GUIs for launching other GUI programs. In fact, we've now come to the end of the demo launcher storyboth of the programs here interact with modules that we met earlier in Chapters 5 and 6:


launchmodes.py

Starts independent Python programs portably.


Launcher.py

Finds programs, and ultimately runs both PyDemos and PyGadgets when used by the self-configuring top-level launcher scripts.


LaunchBrowser.py

Spawns web browsers.

See Example 5-25 in Chapter 5, and Examples 6-14 and 6-15 in Chapter 6, for the code for these modules. The programs listed here add the GUI components to the program-launching systemthey simply provide easy-to-use pushbuttons that spawn most of the larger examples in this text when pressed.

Both of these scripts also assume that they will be run with the current working directory set to their directory (they hardcode paths to other programs relative to that). Either click on their names in a file explorer or run them from a command-line shell after a cd to the top-level PP3E examples root directory. These scripts could allow invocations from other directories by prepending the PP3EHOME environment variable's value to program script paths, but they were really designed to be run only out of the PP3E root.

10.9.1. PyDemos Launcher Bar

The PyDemos script constructs a bar of buttons that run programs in demonstration mode, not for day-to-day use. I use PyDemos to show off Python programsit's much easier to press its buttons than to run command lines or fish through a file explorer GUI to find scripts. You should use PyDemos to start and interact with examples presented in this bookall of the buttons on this GUI represent examples we will meet in later chapters.

To make this launcher bar even easier to run, drag it out to your desktop to generate a clickable Windows shortcut (do something similar on other systems). Since this script hardcodes command lines for running programs elsewhere in the examples tree, it is also useful as an index to major book examples. Figure 10-41 shows what PyDemos looks like when run on Windows; it looks slightly different but works the same on Linux.

Figure 10-41. PyDemos with its pop ups


The source code that constructs this scene is listed in Example 10-33. PyDemos doesn't present much that's new in terms of GUI interface programming; its demoButton function simply attaches a new button to the main window, spring-loaded to spawn a Python program when pressed. To start programs, PyDemos calls an instance of the launchmodes.PortableLauncher object we met at the end of Chapter 5its role as a Tkinter callback handler here is why a call operation is used to kick off the launched program.

For this third edition of the book, I've also added "code" buttons to the right of each demo's button, which open the source files that implement the associated example. These files open in pop-up versions of the PyEdit text editor that we'll meet in Chapter 12. This version also sets the main window's icon where applicable and attempts to spawn a locally running web server for web-based demos (we'll meet the server in Chapter 16).

As pictured in Figure 10-41, PyDemos also constructs two pop-up windows when buttons at the bottom of the main window are pressedan Info pop up giving a short description of the last demo spawned, and a Links pop up containing radio buttons that open a local web browser on book-related sites when pressed:

  • The Info pop up displays a simple message line and changes its font every second to draw attention to itself; since this can be a bit distracting, the pop up starts out iconified (click the Info button to see or hide it).

  • The Links pop up's radio buttons are much like hyperlinks in a web page, but this GUI isn't a browser: when the Links pop up is pressed, the portable LaunchBrowser script we met in Chapter 6 is used to find and start a web browser used to connect to the relevant site, assuming you have an Internet connection.

  • A module we'll meet in the next chapter, named windows, is used to give this GUI's windows a blue "PY" icon, instead of the standard red "Tk."

PyDemos runs on Windows and Linux, but that's largely due to the inherent portability of both Python and Tkinter. For more details, consult the source, which is shown in Example 10-33.

Example 10-33. PP3E\PyDemos2.pyw

 ################################################################################ # PyDemos2.pyw # Programming Python, 2nd and 3rd Edition (PP3E), 1999--2006 # Version 2.0, March '06: add source-code file viewer buttons, new demos # (PyPhoto, PyMailGUI2), spawn locally running web server for browser-based # demos, window icons, and probably other things I've forgotten :-). # # Launch major Python+Tk GUI examples from the book, in a platform-neutral way. # This file also serves as an index to major program examples, though many book # examples aren't GUI-based, and so aren't listed here (e.g., see the Cygwin # gcc makefiles in the Integration directory for C integration code pointers). # Also see: # # - PyGadgets.py, a simpler script for starting programs in non-demo mode #   that you wish to use on a regular basis # - PyGadgets_bar.pyw, which creates a button bar for starting all PyGadgets #   programs on demand, not all at once # - Launcher.py for starting programs without environment settings--finds #   Python, sets PYTHONPATH, etc. # - Launch_*.py for starting PyDemos and PyGadgets with Launcher.py--run these #   for a quick look # - LaunchBrowser.py for running example web pages with an automatically #   located web browser # - README-PP3E.txt, for general examples information # # This program tries to start a locally running web server and web browser # automatically, for web-based denmos.  Additional program comments # were moved to file PyDemos.doc.txt ################################################################################ import sys, time, os, glob, launchmodes from Tkinter import * # -live loads root pages from server so CGIs run, -file loads local files InternetMode = '-live' ################################################################################ # start building main GUI windows ################################################################################ from PP3E.Gui.Tools.windows import MainWindow    # a Tk with icon, title, quit from PP3E.Gui.Tools.windows import PopupWindow   # same but Toplevel, diff quit Root = MainWindow('PP3E Demos 2.0') # build message window Stat = PopupWindow('PP2E demo info') Stat.protocol('WM_DELETE_WINDOW', lambda:0)      # ignore wm delete Info = Label(Stat, text = 'Select demo',              font=('courier', 20, 'italic'), padx=12, pady=12, bg='lightblue') Info.pack(expand=YES, fill=BOTH) ################################################################################ # add launcher buttons with callback objects ################################################################################ from PP3E.Gui.TextEditor.textEditor import TextEditorMainPopup # demo launcher class class Launcher(launchmodes.PortableLauncher):    # use wrapped launcher class     def announce(self, text):                    # customize to set GUI label         Info.config(text=text) def viewer(sources):     for filename in sources:         TextEditorMainPopup(Root, filename)      # as pop up in this process def demoButton(name, what, doit, code):     rowfrm = Frame(Root)     rowfrm.pack(side=TOP, expand=YES, fill=BOTH)     b = Button(rowfrm, bg='navy', fg='white', relief=RIDGE, border=4)     b.config(text=name, width=20, command=Launcher(what, doit))     b.pack(side=LEFT, expand=YES, fill=BOTH)     b = Button(rowfrm, bg='beige', fg='navy')     b.config(text='code', command=(lambda: viewer(code)))     b.pack(side=LEFT, fill=BOTH) # some imported module source files could be determined # but we can't know where to stop on the import chains ################################################################################ # Tkinter GUI demos - some use network connections ################################################################################ demoButton(name='PyEdit',            what='Text file editor',                            # edit myself            doit='Gui/TextEditor/textEditor.py PyDemos2.pyw',   # assume in cwd            code=['Gui/Tools/guimaker.py',                      # show viewer                  'Gui/TextEditor/textEditor.py']) demoButton(name='PyView',            what='Image slideshow, plus note editor',            doit='Gui/SlideShow/slideShowPlus.py Gui/gifs',            code=['Gui/Texteditor/textEditor.py',                  'Gui/SlideShow/slideShowPlus.py',                  'Gui/SlideShow/slideShow.py']) demoButton(name='PyDraw',            what='Draw and move graphics objects',            doit='Gui/MovingPics/movingpics.py Gui/gifs',            code=['Gui/MovingPics/movingpics.py']) demoButton(name='PyTree',            what='Tree data structure viewer',            doit='Dstruct/TreeView/treeview.py',            code=['Dstruct/TreeView/treeview.py',                  'Dstruct/TreeView/treeview_wrappers.py',                  'Dstruct/Classics/btree.py',                  'Lang/Parser/parser2.py']) demoButton(name='PyClock',            what='Analog/digital clocks',            doit='Gui/Clock/clockStyles.py Gui/gifs',            code=['Gui/Tools/windows.py',                  'Gui/Clock/clockStyles.py',                  'Gui/Clock/clock.py']) demoButton(name='PyToe',            what='Tic-tac-toe game (AI)',            doit='Ai/TicTacToe/tictactoe.py',            code=['Ai/TicTacToe/tictactoe.py',                  'Ai/TicTacToe/tictactoe_lists.py']) demoButton(name='PyForm',                              # view in-memory dict            what='Persistent table viewer/editor',      # or cwd shelve of class            doit='Dbase/TableBrowser/formgui.py',       # 0=do not reinit shelve           #doit='Dbase/TableBrowser/formtable.py  shelve 0 pyformData-1.5.2',           #doit='Dbase/TableBrowser/formtable.py  shelve 1 pyformData',            code=['Dbase/TableBrowser/formgui.py',                  'Dbase/TableBrowser/formtable.py']) demoButton(name='PyCalc',            what='Calculator, plus extensions',            doit='Lang/Calculator/calculator_plusplus.py',            code=['Lang/Calculator/calculator_plusplus.py',                  'Lang/Calculator/calculator_plus_ext.py',                  'Lang/Calculator/calculator_plus_emb.py',                  'Lang/Calculator/calculator.py']) demoButton(name='PyFtp',            what='Python+Tk ftp clients',            doit='Internet/Ftp/PyFtpGui.pyw',            code=['Internet/Ftp/PyFtpGui.pyw',                  'Internet/Ftp/getfilegui.py',                  'Internet/Ftp/putfilegui.py',                  'Internet/Ftp/getfile.py',                  'Internet/Ftp/putfile.py',                  'Internet/Sockets/form.py']) # caveat: PyPhoto requires PIL to be installed: show note demoButton(name='PyPhoto',            what='PIL thumbnail image viewer',            doit='Gui/PIL/pyphoto1.py Gui/PIL/images',     # script, image dir            code=['PyDemos-pil-note.txt',                  'Gui/PIL/viewer_thumbs.py',                  'Gui/PIL/pyphoto1.py']) # get pymailgui source files locat  = 'Internet/Email' locat2 = locat + '/PyMailGui' saved  = '%s/SavedMail/savemany.txt %s/SavedMail/savefew.txt' % (locat2, locat2) source = glob.glob(locat + '/PyMailGui/*.py') # 9 source files here + _ _init_ _ source+= glob.glob(locat + '/mailtools/*.py') # 4 source files here + _ _init_ _ demoButton(name='PyMailGUI2',            what='Python+Tk pop/smtp email client',          # open on save file            doit='%s/PyMailGui2.py %s' % (locat2, saved),            code=(['Gui/Texteditor/textEditor.py',                   'Gui/Tools/windows.py',                   'Gui/Tools/threadtools.py'] + source) ) ################################################################################ # web-based demos - PyInternet opens many smaller demos ################################################################################ # get pymailcgi source files - not incl mailtools! pymailcgifiles = (['Internet/Web/PyMailCgi/pymailcgi.html'] +                   glob.glob('Internet/Web/PyMailCgi/cgi-bin/*.py'))  # 11 .py if InternetMode == '-file':     pagepath = os.getcwd( ) + '/Internet/Web'     demoButton('PyMailCGI2',                'Browser-based pop/smtp email interface',                'LaunchBrowser.pyw -file %s/PyMailCgi/pymailcgi.html' % pagepath,                pymailcgifiles)     demoButton('PyInternet',                'Internet-based demo launcher page',                'LaunchBrowser.pyw -file %s/PyInternetDemos.html' % pagepath,                ['Internet/Cgi-Web/PyInternetDemos.html']) else:     def startLocalWebServers( ):         """         on Windows succeeds silently if server already listening         on the port; caveat: should only run 1 server per port;         global per-process flag won't fix: the servers live on         """         launchmodes.PortableLauncher('server80',             'Internet/Web/webserver.py Internet/Web')( )         launchmodes.PortableLauncher('server8000',             'Internet/Web/webserver.py Internet/Web/PyMailCgi 8000')( )     site = 'localhost:%s'     startLocalWebServers( )  # run webserver on port 80 and 8000 on localhost     print 'servers started'     # PyErrata removed in 3rd Ed     demoButton('PyMailCGI2',                'Browser-based pop/smtp email interface',                'LaunchBrowser.pyw -live pymailcgi.html '+ (site % 8000),                pymailcgifiles)     demoButton('PyInternet',                'Main Internet demos launcher page',                'LaunchBrowser.pyw -live PyInternetDemos.html ' + (site % 80),                ['Internet/Web/PyInternetDemos.html']) #To try: bind mouse entry events to change info text when over a button #See also: site http://starship.python.net/~lutz/PyInternetDemos.html ################################################################################ # toggle info message box font once a second ################################################################################ def refreshMe(info, ncall):     slant = ['normal', 'italic', 'bold', 'bold italic'][ncall % 4]     info.config(font=('courier', 20, slant))     Root.after(1000, (lambda: refreshMe(info, ncall+1)) ) ################################################################################ # unhide/hide status box on info clicks ################################################################################ Stat.iconify( ) def onInfo( ):     if Stat.state( ) == 'iconic':         Stat.deiconify( )     else:         Stat.iconify( )  # was 'normal' ################################################################################ # pop up a few web link buttons if connected ################################################################################ radiovar = StringVar( ) # use a global def onLinks( ):     popup = PopupWindow('PP3E web site links')     links = [("Book",                    'LaunchBrowser.pyw -live about-pp.html www.rmi.net/~lutz'),              ("Python",                    'LaunchBrowser.pyw -live index.html www.python.org'),              ("O'Reilly",                    'LaunchBrowser.pyw -live index.html www.oreilly.com'),              ("Author",                    'LaunchBrowser.pyw -live index.html www.rmi.net/~lutz')]     for (name, command) in links:         callback = Launcher((name + "'s web site"), command)         link = Radiobutton(popup, text=name, command=callback)         link.config(relief=GROOVE, variable=radiovar, value=name)         link.pack(side=LEFT, expand=YES, fill=BOTH)     Button(popup, text='Quit', command=popup.destroy).pack(expand=YES,fill=BOTH)     if InternetMode != '-live':         from tkMessageBox import showwarning         showwarning('PP3E Demos', 'Web links require an Internet connection') ################################################################################ # finish building main GUI, start event loop ################################################################################ Button(Root, text='Info',  command=onInfo).pack(side=TOP, fill=X) Button(Root, text='Links', command=onLinks).pack(side=TOP, fill=X) Button(Root, text='Quit',  command=Root.quit).pack(side=BOTTOM, fill=X) refreshMe(Info, 0)  # start toggling Root.mainloop( ) 

10.9.2. PyGadgets Launcher Bar

The PyGadgets script runs some of the same programs as PyDemos, but for real, practical use, not as flashy demonstrations. Both scripts use launchmodes to spawn other programs and display bars of launcher buttons, but this one is a bit simpler because its task is more focused. PyGadgets also supports two spawning modes: it can either start a canned list of programs immediately and all at once, or display a GUI for running each program on demand. (Figure 10-42 shows the launch bar GUI made in on-demand mode.)

Figure 10-42. PyGadgets launcher bar


Because of such differences, PyGadgets takes a more data-driven approach to building the GUI: it stores program names in a list and steps through it as needed, instead of using a sequence of precoded demoButton calls. The set of buttons on the launcher bar GUI in Figure 10-42, for example, depends entirely upon the contents of the programs list.

The source code behind this GUI is listed in Example 10-34; it's not much because it relies on other modules (launchmodes, LaunchBrowser) to work most of its magic. PyGadgets is always open on my machines (I have a clickable shortcut to this script on my Windows desktop too). I use it to gain easy access to Python tools that I use on a daily basistext editors, calculators, email and photo tools, and so onall of which we'll meet in upcoming chapters.

To customize PyGadgets for your own use, simply import and call its functions with program command-line lists of your own or change the mytools list of spawnable programs near the end of this file. This is Python, after all.

Example 10-34. PP3E\PyGadgets.py

 #!/bin/env python ############################################################################## # Start various examples; run me at system boot time to make them always # available.  This file is meant for starting programs you actually wish # to use; see PyDemos for starting Python/Tk demos and more details on # program start options.  Windows usage note: this is a '.py' file, so you # get a DOS box console window when it is clicked; the DOS box is used to # show a startup message (and we sleep 5 seconds to make sure it's visible # while gadgets start up).  If you don't want the DOS pop up, run with the # 'pythonw' program (not 'python'), use a '.pyw' suffix, mark with a 'run # minimized' Windows property, or spawn the file from elsewhere; see PyDemos. ############################################################################## import sys, time, os, time from Tkinter import * from launchmodes import PortableLauncher           # reuse program start class def runImmediate(mytools):     # launch gadget programs immediately     print 'Starting Python/Tk gadgets...'          # msgs to temp stdout screen     for (name, commandLine) in mytools:         PortableLauncher(name, commandLine)( )          # call now to start now     print 'One moment please...'                   # \b means a backspace     if sys.platform[:3] == 'win':         # on Windows keep stdio console window up for 5 seconds         for i in range(5): time.sleep(1); print ('\b' + '.'*10), def runLauncher(mytools):     # put up a simple launcher bar for later use     root = Tk( )     root.title('PyGadgets PP3E')     for (name, commandLine) in mytools:         b = Button(root, text=name, fg='black', bg='beige', border=2,                    command=PortableLauncher(name, commandLine))         b.pack(side=LEFT, expand=YES, fill=BOTH)     root.mainloop( ) mytools = [     ('PyEdit',   'Gui/TextEditor/textEditor.py'),     ('PyCalc',   'Lang/Calculator/calculator.py'),     ('PyPhoto',  'Gui/PIL/pyphoto1.py Gui/PIL/images'),     ('PyMail',   'Internet/Email/PyMailGui/PyMailGui2.py'),     ('PyClock',  'Gui/Clock/clock.py -size 175 -bg white'                           ' -picture Gui/gifs/pythonPowered.gif'),     ('PyToe',    'Ai/TicTacToe/tictactoe.py'                           ' -mode Minimax -fg white -bg navy'),     ('PyWeb',    'LaunchBrowser.pyw'                           ' -live PyInternetDemos.html localhost:80') ]                                       # PyWeb assumes local server started if _ _name_ _ == '_ _main_ _':     prestart, toolbar = 1, 0     if prestart:         runImmediate(mytools)     if toolbar:         runLauncher(mytools) 

By default, PyGadgets starts programs immediately when it is run. To run PyGadgets in launcher bar mode instead, Example 10-35 simply imports and calls the appropriate function with an imported program list. Because it is a .pyw file, you see only the launcher bar GUI it constructs initially, not a DOS console streams window.

Example 10-35. PP3E\PyGadgets_bar.pyw

 # run PyGadgets toolbar only, instead of starting all the # gadgets immediately; filename avoids DOS pop up on Windows import PyGadgets PyGadgets.runLauncher(PyGadgets.mytools) 

This script is the file my desktop shortcut invokes; I prefer to run gadget GUIs on demand. You can also run a script like this at your system's startup to make it always available (and to save a mouse click). For instance:

  • On Windows, such a script can be automatically started by adding it to your StartUp folderclick on your system's Start button, select Settings, go to the Taskbar & Start Menu dialog, and click your way through the remaining steps.

  • On Linux and Unix, you can automatically start this script by spawning it with a command line in your startup scripts (e.g., your home directory's .cshrc, .profile, or .login) after X Windows has been started.

Whether run via a shortcut, a file explorer click, a typed command line, or other means, the PyGadgets launcher bar at the top of Figure 10-43 appears.

Figure 10-43. PyGadgets launcher bar with gadgets


Of course, the whole point of PyGadgets is to spawn other programs. Pressing on its launcher bar's buttons starts programs like those shown in the rest of Figure 10-43, but if you want to know more about those, you'll have to turn the page and move on to the next chapter.




Programming Python
Programming Python
ISBN: 0596009259
EAN: 2147483647
Year: 2004
Pages: 270
Authors: Mark Lutz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net