#!/usr/bin/env python
#
# $Id: GuiAppD.py,v 1.8 2002/06/20 13:04:49 doughellmann Exp $
#
# Copyright 2001 Doug Hellmann.
#
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice appear in all
# copies and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of Doug
# Hellmann not be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior
# permission.
#
# DOUG HELLMANN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
# NO EVENT SHALL DOUG HELLMANN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
"""GUI application framework providing many common GUI services.
"""
__rcs_info__ = {
#
# Creation Information
#
'module_name' : '$RCSfile: GuiAppD.py,v $',
'rcs_id' : '$Id: GuiAppD.py,v 1.8 2002/06/20 13:04:49 doughellmann Exp $',
'creator' : 'Doug Hellmann <doug@hellfly.net>',
'project' : 'PmwContribD',
'created' : 'Sun, 01-Apr-2001 13:03:01 EDT',
#
# Current Information
#
'author' : '$Author: doughellmann $',
'version' : '$Revision: 1.8 $',
'date' : '$Date: 2002/06/20 13:04:49 $',
}
#
# Import system modules
#
import sys
import string
import os
from Tkinter import *
import Pmw
import tkFileDialog
#
# Import Local modules
#
import geometrystring
import HelpTree
import PrefsDialog
import ProgressMeter
#
# Module
#
class GuiAppD(Pmw.MegaWidget):
"""This class is designed to be a GUI application framework.
This class creates a simple application dialog including a
menubar, status message area, progress meter, help and about
dialogs. The class methods also provide simple access to features
of Pmw and Tkinter such as
- changing the cursor during a busy processing time
- displaying message and error dialogs
- providing menu bar items.
- registering documentation as part of the built-in online help
system
- status messages,
The class acts as the base class for simple GUI applications,
making the job of creating a small application to perform a simple
task easy. The constructor manages all of the startup and
initialization required for Tk, Tkinter, and Pmw. A subclass
defines a method to create the interface for the application, and
(optionally) a method to perform application initialization. An
instance is created, and the run method is then used to run the
application.
Since this class is a base class, the user expected to subclass it
and override several attributes as well as the createinterior()
method in order to create an application.
The documentation for each method indicates whether it should be
overridden by the subclass or not. There are three types of
methods:
*Override* -- This method should be overridden.
*Override ok* -- This method can be overridden, but maybe
shouldn't be and should not need to be.
*No override* -- Do not override this method.
Class Attributes to Override
'appversion' -- *string*
What version of your application is this?
'appname' -- *string*
What is the name of your application?
'contactname' -- *string*
Name of the person to contact when the user has questions.
'copyrightname' -- *string*
Name of the person holding copyright to the app.
'copyright' -- *string*
Copyright notice for the app.
'contactphone' -- *string*
Recommended for use only with apps used by other members of
your organization. This information will be included in the
**About** dialog.
'contactemail' -- *string*
Email address to use to request help about the app.
'resizeWidth' -- *integer*
If true, the user is allowed to resize the main dialog width.
'resizeHeight' -- *integer*
If true, the user is allowed to resize the main dialog height.
'padx' -- *integer*
X padding for spacing between widgets.
'pady' -- *integer*
Y padding for spacing between widgets.
'usebuttonbox' -- *integer*
If true, build a button box area of the GUI app to provide
quick buttons for some actions. This area is not created if
false. Defaults to false.
Options
'balloon_state="both"' -- The type of help provided by the
balloon manager. Valid options are described in the
documentation for the Pmw.Balloon class.
'padx' -- Internal X spacing for child widgets.
'pady' -- Internal Y spacing for child widgets.
'resizeheight=1' -- Boolean controlling whether the application
frame will allow resizing in the Y direction. The default,
true, means resizing will be allowed.
'resizewidth=1' -- Boolean controlling whether the application
frame will allow resizing in the X direction. The default,
true, means resizing will be allowed.
'usebuttonbox=0' -- Boolean controlling whether the
Pmw.ButtonBox portion of the interface is *packed* (it is always
created).
Components
'balloon' -- This component is a Pmw.Balloon, and is
automatically tied to the message area of the application
window.
'bottomtray' -- This component is a Tkinter.Frame which contains
the message bar and progress meter at the very bottom of the
application window.
'buttonbox' -- This component is a Pmw.ButtonBox used for the set
of buttons arranged along the bottom of the main application
window. The class attribute usebuttonbox controls whether or not
the button box is displayed.
'dialogchildsite' -- This component is a Tkinter.Frame and is
used for the container of application interface components. This
is the widget returned by the 'interior()' method of the
GuiAppD.
'hull' -- This acts as the body for the entire megawidget. Other
components are created as children of the hull to further
specialise the widget. By default, this component is a
Tkinter.Frame.
'menubar' -- This acts as the main menu for the entire
application. Submenus which are automatically created are *File*
and *Help*. Other submenus and menu items can be created by the
subclass.
'messagebar' -- This component is a Pmw.MessageBar displayed at
the bottom left of the application window, inside the
'bottomtray'. The message bar is automatically tied to the
'balloon' component to display status messages. This is also
where messages passed to the 'statusMessage()' method are
displayed.
'progressmeter' -- This component is a PmwContribD.ProgressMeter
displayed at the bottom right of the application window, inside
the bottomtray. See the updateProgress() method.
Screenshots
Take a look at "GuiAppD":images/GuiAppD.gif running on a
Macintosh.
"""
appversion='0.0'
appname='(appname not set)'
contactname='Doug Hellmann'
copyrightname=contactname
copyright='Copyright %s 2002\nAll rights reserved.' % copyrightname
contactphone=''
contactemail='doug@hellfly.net'
resizeWidth = 1
resizeHeight = 1
padx=5
pady=5
usebuttonbox=0
busycursor='watch'
#
# Each subclass should override this value
# with an instance of UserPrefs.
#
user_preferences = {}
if sys.platform == 'mac':
accelerator_prefix = 'Command'
elif sys.platform == 'win32':
accelerator_prefix = 'Control'
else:
accelerator_prefix = 'Control'
def __init__(self, **kw):
optiondefs = (
('balloon_state', 'both', None),
('padx', 1, Pmw.INITOPT),
('pady', 1, Pmw.INITOPT),
('resizewidth', 1, Pmw.INITOPT),
('resizeheight', 1, Pmw.INITOPT),
('usebuttonbox', self.usebuttonbox, Pmw.INITOPT),
)
self.defineoptions(kw, optiondefs)
#
# Initialize the GUI package
#
root = Tk()
self.root = root
self.initializeTk(root)
#Pmw.initialise(root, useTkOptionDb=1)
Pmw.initialise(root)
root.title(self.appname)
root.resizable(self.resizeWidth, self.resizeHeight)
#
# Initialize the GUI base class
#
Pmw.MegaWidget.__init__(self, parent=self.root)
# initialize dialog references for dialogs that will be created later
self.__helpDialog = None
self.__prefsDialog = None
# initialize the app
self.appInit()
# create the help document
self._buildHelpTable()
# create the interface
self._createInterface()
# create a table to hold the cursors for
# widgets which get changed when we go busy
self.preBusyCursors = None
# pack our container and set focus
# to ourselves
self._hull.pack(side=TOP,
fill=BOTH,
expand=YES)
self.focus_set()
# initialize our options
self.initialiseoptions(GuiAppD)
return
def addHelpItem(self, key, text):
"""Add a help item to the help text tree.
Arguments
'key' -- String placing the help node into the tree of
online help. Sections of the path are colon separated.
For example::
w.addHelpItem(Menu:File:Save as..., Save file with new name.)
will insert a help node under the (Menu, File) section of
the help tree. The name of the node will be "Save as..."
and the body of the node will be "Save file with new
name."
'text' -- Help text associated with the key.
"""
#print 'adding "%s"->%s' % (key, text)
self.__helpTable.insert_node(key, text)
return
def buildHelpTable(self):
"""Install help text not associated with specific widgets.
*Override*
"""
self.addHelpItem('Interface',
"""
This section describes the user interface for %s.
""" % self.appname)
self.addHelpItem('Concepts',
"""
This section describes concepts used by %s.
""" % self.appname)
self.addHelpItem('History',
"""
This section details the history of each version of %s.
""" % self.appname)
return
def _buildHelpTable(self):
"""Retrieve all of the help document sections from all classes.
*No override.*
"""
self.__helpTable = HelpTree.HelpTree(self.__class__.__name__,
HelpTree.move_text_left(self.__doc__))
self.buildHelpTable()
#print 'HELP TABLE: ', self.__helpTable
return
def appInit(self):
"""Called before interface is created.
*Override.*
"""
pass
def initializeTk(self, root):
"""Initialize platform specific options
*Override ok.*
"""
if sys.platform == 'mac':
self._initializeTk_mac(root)
elif sys.platform == 'win32':
self._initializeTk_win32(root)
else:
self._initializeTk_unix(root)
return
def _initializeTk_colors_common(self, root):
"""Initialize platform specific color options.
*Override ok.*
"""
root.option_add('*background', 'grey')
root.option_add('*foreground', 'black')
root.option_add('*EntryField.Entry.background', 'white')
root.option_add('*Listbox*background', 'white')
root.option_add('*Listbox*selectBackground', 'dark slate blue')
root.option_add('*Listbox*selectForeground', 'white')
return
def _initializeTk_win32(self, root):
"""Initialize platform specific color options.
*Override ok.*
"""
root.option_add('*Font', 'Helvetica 8')
root.option_add('*EntryField.Entry.Font', 'Courier 8')
root.option_add('*Listbox*Font', 'Courier 8')
return
def _initializeTk_mac(self, root):
"""Initialize platform specific color options.
*Override ok.*
"""
self._initializeTk_colors_common(root)
return
def _initializeTk_unix(self, root):
"""Initialize platform specific color options.
*Override ok.*
"""
self._initializeTk_colors_common(root)
return
def _getHelpTextForClass(self, rClass):
"""Retrieves doc strings for base classes so they can be included in help manual.
*No override.*
"""
if rClass.__doc__:
value = rClass.__doc__
valueList = string.split(value, '\n')
valueList = map(lambda x: x[1:], valueList)
value = string.join(valueList, '\n')
else:
value = ''
return value
def busyStart(self, newcursor=None):
"""Use this to put the UI into busy mode.
Arguments
newcursor -- Optional cursor name to be used while in busy mode.
*Override ok.*
"""
if not newcursor:
newcursor = self.busycursor
newPreBusyCursors = {}
for component in self.busyWidgets:
newPreBusyCursors[component] = component['cursor']
component.configure(cursor=newcursor)
component.update_idletasks()
self.preBusyCursors = (newPreBusyCursors, self.preBusyCursors)
return
def busyEnd(self):
"""Take the UI out of busy mode.
*Override ok.*
"""
if not self.preBusyCursors:
return
oldPreBusyCursors = self.preBusyCursors[0]
self.preBusyCursors = self.preBusyCursors[1]
for component in self.busyWidgets:
try:
component.configure(cursor=oldPreBusyCursors[component])
except KeyError:
pass
component.update_idletasks()
return
def _getHelpTextRecurse(self, rClass):
"""Get the help text for the base classes.
*No override.*
"""
value=self._getHelpTextForClass(rClass)
for c in rClass.__bases__:
value = value + self._getHelpTextRecurse(c)
return value
def _getHelpText(self):
"""Get the help text for this class and its base classes.
*No override.*
"""
#txt = self._getHelpTextRecurse(self.__class__)
try:
txt = self.helpText
except AttributeError:
txt = ''
if not txt:
txt = self._getHelpTextForClass(self.__class__)
if not txt:
txt = """\
Define the __doc__ string or helpText
for the application class to specify the
help message.
"""
#
# Clean up text
#
original_len = len(txt)
no_left_margin = string.lstrip(txt)
new_len = len(no_left_margin)
indent=original_len - new_len
if sys.platform == 'mac':
spliton = '\r'
else:
spliton = '\n'
help_lines_list = string.split(txt, spliton)
value = ''
for line in help_lines_list:
line = string.rstrip(line)
line = line[indent-1:]
value = '%s%s\n' % (value, line)
return value
def _createAboutBox(self):
"""Creates the *About* dialog.
Handle to the dialog is stored as 'w.about'.
*Override ok.*
"""
Pmw.aboutversion(self.appversion)
Pmw.aboutcopyright(self.copyright)
Pmw.aboutcontact(
'For more information, contact:\n %s\n Phone: %s\n Email: %s' % (
self.contactname,
self.contactphone,
self.contactemail
))
self.about = Pmw.AboutDialog(self._hull,
applicationname=self.appname)
self.about.withdraw()
return None
def showAbout(self):
"""Shows the *About* dialog.
Input is blocked by the dialog until the user presses ok.
*Override ok.*
"""
self.about.show()
self.about.focus_set()
return
def _createMenuBar(self):
"""Create the menu bar for the app.
Creates a Pmw.MenuBar as component named 'menubar' and stores
a handle in 'w.menuBar'. Several default menus are added at
the same time.
*No override.*
"""
self.menuBar = self.createcomponent('menubar', (), None,
Pmw.MenuBar,
(self._hull,),
hull_relief=RAISED,
hull_borderwidth=1,
balloon=self.balloon()
)
self.menuBar.pack(fill=X)
try:
self.menuBar.addmenu('Help', 'User manuals', side=RIGHT)
except ValueError:
pass
else:
self.addHelpItem('Interface:Menu:Help',
"""
Provides help for %s.
""" % self.appname)
try:
self.menuBar.addmenu('File', 'File commands and Quit')
except ValueError:
pass
else:
self.addHelpItem('Interface:Menu:File',
"""
Provides access to file related functions.
""")
try:
self.menuBar.addmenu('Options', 'Set application options')
except ValueError:
pass
else:
self.addHelpItem('Interface:Menu:Options',
"""
Provides access to application options.
""")
return
def addMenuItem(self, menuName, itemType, helpText, label, command,
accelerator='', acceleratorKey='', binding=None, **kw):
"""Add a new item to the menu structure for the app.
Add a new menu item with name 'label' in the menu 'menuName'.
When the menu item is invoked, 'command' will be called.
If 'acceleratorKey' is specified, a binding for a platform-dependant
accelerator_prefix with that one character key will be created
on the application toplevel window. If 'accelerator' and
'binding' are specified, and 'acceleratorKey' is not, the
binding and accelerator are taken as specified.
Arguments
'menuName' -- Name of the menu into which item should be added.
'itemType' -- Type of the item to insert (usually 'command').
'helpText' -- Balloon help for the menu item.
'label' -- Text to appear on the item button.
'command' -- Function to call when item is selected.
'accelerator' -- Used in combination with 'binding' if
'acceleratorKey' not specified.
'acceleratorKey' -- String with one key which should be set
as the keyboard accelerator to access the menu item
directly.
'binding' -- Keybinding which should invoke the menu item.
*Override ok.*
"""
if acceleratorKey:
accelerator='%s-%s' % (self.accelerator_prefix, acceleratorKey)
binding='<%s-%s>' % (self.accelerator_prefix, acceleratorKey)
itemopts = {
'label':label,
'command':command,
'accelerator':accelerator,
}
itemopts.update(kw)
apply(self.menuBar.addmenuitem, (menuName, itemType, helpText),
itemopts)
if binding:
self._hull.bind_all(binding, command)
return
def toggleBalloon(self):
"""Control whether or not the balloon help is displayed.
Looks into the w.toggleBalloonVar value to determine if the
balloon help should be turned on or off.
*Override ok.*
"""
if self.toggleBalloonVar.get():
self.__balloon.configure(state = 'both')
else:
self.__balloon.configure(state = 'status')
return
def quit(self, *args):
"""Exit the app.
*Override ok.*
"""
Pmw.MegaWidget.quit(self)
return
def createMenuBar(self):
"""Create the menu bar for this application class.
*Override ok.*
"""
#
# About box
#
self.addHelpItem('Interface:Menu',
"""
Describes the menus available in %s.
""" % self.appname)
self.addMenuItem('Help', 'command', 'About this application',
label='About...',
command=self.showAbout
)
self.addHelpItem('Interface:Menu:Help:About',
"""
Lists the author and contact information for %s,
along with version data.
""" % self.appname
)
#
# Online help manual
#
self.addMenuItem( 'Help',
'command',
'Help for this application',
label='Manual',
command=self.showHelpDialog,
accelerator='F1',
binding = '<F1>',
)
self.addHelpItem('Interface:Menu:Help:Manual', ' Invokes this dialog.')
#
# Toggle balloon help
#
self.toggleBalloonVar = IntVar()
try:
self.toggleBalloonVar.set(os.environ['PMW_BALLOON_HELP'])
except KeyError:
self.toggleBalloonVar.set(1)
self.addMenuItem('Help',
'checkbutton',
'Use balloon help',
label='Use balloon help',
variable=self.toggleBalloonVar,
command=self.toggleBalloon,
)
self.toggleBalloon()
self.addHelpItem('Interface:Menu:Help:Turn on balloon help',
'Enable the floating tool-tip help for each widget.')
#
# Exit the application
#
self.addMenuItem('File', 'command', 'Quit this application',
label='Quit',
command=self.quit,
acceleratorKey='q',
)
self.addHelpItem('Interface:Menu:File:Quit',
"Exits %s." % self.appname)
#
# Edit user preferences for this application
#
self.addMenuItem('Options', 'command', 'Set user preferences',
label='Preferences...',
command=self.showPrefsDialog,
)
self.addHelpItem('Interface:Menu:Options:Preferences...',
"User preferences for %s." % self.appname)
return
def showPrefsDialog(self):
"""Display the preferences dialog for the application.
*No override.*
"""
if not self.__prefsDialog:
self._createPrefsDialog()
self.__prefsDialog.configure(scrolledframe_clipper_width=500)
self.__prefsDialog.activate()
return
def savePrefsCB(self, prefs):
"""Callback to be invoked when preferences are saved.
*Override.*
"""
pass
def _createPrefsDialog(self):
"""Create the preferences dialog for this app.
The preferences dialog requires a UserPrefs instance. See
PrefsDialog and UserPrefs modules.
*No override.*
"""
self.__prefsDialog = PrefsDialog.PrefsDialog(
parent=self._hull,
userPrefs=self.user_preferences,
title='Preferences for %s' % self.appname,
savecommand=self.savePrefsCB,
)
return
def createHelpButton(self):
"""Add a help button to the button box.
*Override ok.*
"""
self.buttonAdd('Help',
helpMessage='Show help',
statusMessage='Show help',
command=self.showHelpDialog)
return
def showHelpDialog(self, event=None):
"""Display the help dialog.
*Override ok.*
"""
if not self.__helpDialog:
self._createHelpDialog()
self.__helpExplorer.component('navigator').configure(
treedata=self.__helpTable)
self.__helpDialog.show()
self.__helpDialog.focus_set()
return
def _createHelpDialog(self):
"""Create the dialog to display the help message.
*No override.*
"""
self.__helpDialog = self.createcomponent('helpdialog', (), None,
Pmw.Dialog,
(self._hull,),
defaultbutton=0,
title='Help for %s' % self.appname,
)
self.__helpDialog.geometry('800x400')
self.__helpExplorer = self.createcomponent('helpexplorer', (), None,
HelpTree.HelpExplorer,
(self.__helpDialog.interior(),),
)
self.__helpExplorer.pack(side=TOP, expand=YES, fill=BOTH)
#self.__helpDialog.withdraw()
#self.__helpDialog.insert('end', self._getHelpText())
return
def _createBalloon(self):
"""Create the balloon help manager for the frame.
*No override.*
"""
# Create the manager for the balloon help
self.__balloon = self.createcomponent('balloon', (), None,
Pmw.Balloon, (self._hull,))
return
def balloon(self):
"""Return the balloon help manager.
*No override.*
"""
return self.__balloon
def _createChildSite(self):
"""Create a place where children of the main dialog should be placed.
Creates a component 'dialogchildsite' which is a child of main
application window. Default widget type for the component is
a Frame.
*Override ok.*
"""
# Create the child area
self.dialogChildSite = self.createcomponent('dialogchildsite',
(), None,
Frame, (self._hull,),
relief=GROOVE,
bd=1)
self.dialogChildSite.pack(side=TOP,
fill=BOTH,
expand=YES,
padx=self['padx'],
pady=self['pady'])
return
def _createButtonBox(self):
"""Create a button box for holding application wide buttons.
Creates a component 'buttonbox' as a Pmw.ButtonBox. The
widget is only packed if the 'usebuttonbox' option is enabled.
*Override ok.*
"""
self.__bbFrame = self.createcomponent('bbframe', (), None,
Frame,
(self._hull,),
#relief=GROOVE,
relief=SUNKEN,
bd=2)
self.__buttonBox = self.createcomponent('buttonbox', (), None,
Pmw.ButtonBox,
(self.__bbFrame,),
padx=0, pady=0,
#hull_relief=SUNKEN,
#hull_bd=2,
)
self.idleWidgets.append(self.__buttonBox)
self.__buttonBox.pack(side=TOP,
expand=NO,
fill=X)
if self['usebuttonbox']:
self.__bbFrame.pack(side=TOP,
expand=NO,
fill=X,
padx=self['padx'],
pady=self['pady'])
return
def _createMessageBar(self):
"""Create the message bar area for help and status messages.
Creates components 'bottomtray' (a Frame), 'messagebar' (a
Pmw.MessageBar), and 'progressmeter' (a ProgressMeter).
*Override ok.*
"""
frame = self.createcomponent('bottomtray', (), None,
Frame,
(self._hull,),
relief=SUNKEN,
)
self.__messageBar = self.createcomponent('messagebar',
(), None,
Pmw.MessageBar,
(frame,),
entry_width = 40,
entry_relief=SUNKEN,
entry_bd=1,
labelpos=None,
)
self.__messageBar.pack(side=LEFT,
expand=YES,
fill=X,
)
self.__progressMeter = self.createcomponent(
'progressmeter',
(), None,
ProgressMeter.ProgressMeter,
(frame,),
progresscolor='slateblue',
showindicator=1,
meter_width=150
)
self.__progressMeter.pack(
side=LEFT,
expand=NO,
fill=NONE,
)
self.updateProgress(0)
frame.pack(side=BOTTOM,
expand=NO,
fill=X,
)
self.__balloon.configure(statuscommand = self.__messageBar.helpmessage)
return
def updateProgress(self, newValue=0, newLimit=0):
"""Show progress.
Arguments
'newValue' -- The new progress state.
'newLimit' -- The new maximum limit value for the progress
meter. (See ProgressMeter for more details.)
*Override ok.*
"""
if newLimit:
self.__progressMeter.configure(finishvalue=newLimit)
self.__progressMeter.updateProgress(newValue)
return
def bind(self, child, balloonHelpMsg, statusHelpMsg=None):
"""Bind a help message and/or status message to a widget.
Arguments
'child' -- Widget with which the help message is associated.
'balloonHelpMsg' -- Text to show in balloon help popup.
'statusHelpMsg' -- Text to show in message bar.
*Override ok.*
"""
self.__balloon.bind(child, balloonHelpMsg, statusHelpMsg)
return
def interior(self):
"""Retrieve the interior site where children should go.
*Override ok.*
"""
return self.dialogChildSite
def buttonBox(self):
"""Retrieve the button box.
*Override ok.*
"""
return self.__buttonBox
def buttonAdd(self, buttonName, helpMessage=None, statusMessage=None, **kw):
"""Add a button to the button box. Returns the new button.
Arguments
'buttonName' -- Text to appear on the button.
'helpMessage' -- Help text to be registered.
'statusMessage' -- Help text to be registered.
'**kw' -- Other keyword arguments.
*Override ok.*
"""
newBtn = apply(self.__buttonBox.add, (buttonName,), kw)
#newBtn = self.__buttonBox.add(buttonName)
#newBtn.configure(kw)
if helpMessage:
self.bind(newBtn, helpMessage, statusMessage)
return newBtn
def checkScreenBoundary(self, xCoord, yCoord, wCoord, hCoord):
"""Makes sure message windows do not appear off screen
*No override.*
"""
widthLimit = self._hull.master.winfo_screenwidth()
heightLimit = self._hull.master.winfo_screenheight()
if (xCoord + wCoord > widthLimit - 20):
xCoord = widthLimit - wCoord - 20
elif (xCoord < 20):
xCoord = 20
if ((yCoord + hCoord > heightLimit - 50) or (yCoord < 50)):
yCoord = heightLimit/2 - hCoord/2
xCoord = widthLimit/2 - wCoord/2
return xCoord, yCoord
def centerMessageDialog(self, msgDialog):
"""Centers a message dialog on the screen.
*Obsolete*
"""
return
geoString = self._hull.master.geometry()
dialogGeoString = msgDialog.geometry()
dialogGeo = geometrystring.geoStringToTuple(dialogGeoString)
oldGeo = geometrystring.geoStringToTuple(geoString)
oldW = oldGeo[0]
oldH = oldGeo[1]
oldX = oldGeo[2]
oldY = oldGeo[3]
newW = max(oldGeo[0]*1/2, 250)
newH = max(oldGeo[1]/4, 150)
#newW = dialogGeo[0]
#newH = dialogGeo[1]
newX = (oldX + oldW/2 - newW/2)
newY = (oldY + oldH/2 - newH/2)
newX, newY = self.checkScreenBoundary(newX, newY, newW, newH)
newGeo = geometrystring.geoTupleToString(newW, newH, newX, newY)
msgDialog.geometry(newGeo)
return
def bell(self):
"""Ring the bell as an alert.
*Override ok.*
"""
self._hull.bell()
return
def showError(self, errorMessage):
"""Beep and display errorMessage in a dialog.
*Override ok.*
"""
self.bell()
tmpDialog = Pmw.MessageDialog(self._hull,
title='%s Error' % self.appname,
message_text=errorMessage,
iconpos='w',
icon_bitmap='error')
self.centerMessageDialog(tmpDialog)
tmpDialog.activate()
return
def showMessageDialog(self, messageText, justify='center',
buttons=('OK',),
title=None):
"""Display messageText in a dialog.
*Override ok.*
"""
if title is None:
title='%s Message' % self.appname
tmpDialog = Pmw.MessageDialog(self._hull,
title=title,
message_text=messageText,
message_justify=justify,
defaultbutton='OK',
buttons=buttons)
self.centerMessageDialog(tmpDialog)
return tmpDialog.activate()
def getFilenameToOpen(self,
title='Open File',
filetypes=[('Text Files', '*.txt'),
],
initialdir=None,
):
"""Present a dialog and ask the user for the name of a file to open.
Arguments
title -- Title for the dialog.
filetypes -- Sequence of (label, pattern) tuples. The same
pattern may occur with several titles. Use '"*"' as pattern
to indicate all files.
initialdir -- Initial directory.
"""
filename = tkFileDialog.askopenfilename(title=title,
filetypes=filetypes,
initialdir=initialdir)
return filename
def _createInterface(self):
"""Create the main GUI interface.
*No override.*
"""
self.busyWidgets = [ self.root ]
self.idleWidgets = [ self.root ]
self._createBalloon()
self._createMenuBar()
self._createChildSite()
self._createButtonBox()
self._createMessageBar()
self._createAboutBox()
self._helpDialog = None
self._prefsDialog = None
#
# Create the parts of the interface
# which can be modified by subclasses
#
self.createMenuBar()
self.createInterface()
return
def createInterface(self):
"""Create the interface for the app.
*Override.*
"""
pass
def main(self):
"""Main application processing.
*No override.*
"""
self.pack()
self.mainloop()
return
def run(self):
"""Run the application.
*No override.*
"""
self.main()
return
def showMessage(self, type, msgTxt=None):
"""Show a message in the message bar.
*Override ok.*
"""
if msgTxt:
self.component('messagebar').message(type, msgTxt)
else:
self.component('messagebar').resetmessages(type)
self.component('hull').update_idletasks()
return
def update_idletasks(self):
for widget in self.idleWidgets:
widget.update_idletasks()
Pmw.MegaWidget.update_idletasks(self)
return
if __name__ == '__main__':
class TestGuiApp(GuiAppD):
"""
This is a simple test application to test features of the
GuiApp and AppFrame classes.
"""
q = 0
usebuttonbox=1
def busyPush(self):
for cursorname in ( 'trek', 'box_spiral', 'circle', 'clock',
'X_cursor', 'pirate', 'target', 'star',
'coffee_mug', 'gumby',
):
self.busyStart(cursorname)
def createButtons(self):
self.buttonAdd('Ok',
helpMessage='Exit',
statusMessage='Exit',
command=self.quit)
if self.q:
self.buttonAdd('Quit',
helpMessage='Quit',
statusMessage='Quit',
command=self.quit)
self.buttonAdd('Exception',
helpMessage='Raise an exception',
statusMessage='Raise an exception',
command=self.exceptCB)
self.buttonAdd('Busy On',
helpMessage='Turn on busy cursor',
command=self.busyStart)
self.buttonAdd('Busy Push',
helpMessage='Turn on another cursor',
command=self.busyPush)
self.buttonAdd('Busy Off',
helpMessage='Turn off busy cursor',
command=self.busyEnd)
self.buttonAdd('About',
helpMessage='Show about dialog',
statusMessage='Show about dialog',
command=self.showAbout)
self.createHelpButton()
def exceptCB(self):
raise 'ExceptionName', 'exception data'
def createMain(self):
self.label = self.createcomponent('label', (), None,
Label,
(self.interior(),),
text='Hi there')
self.label.pack()
self.bind(self.label, 'Space taker')
def createInterface(self):
GuiAppD.createInterface(self)
self.createButtons()
self.createMain()
#tga = TestGuiApp()
#tga.run()
tga2 = TestGuiApp()
tga2.run()
|