awips2/pythonPackages/scientific/Scientific/TkWidgets/Utility.py
root 06a8b51d6d Initial revision of AWIPS2 11.9.0-7p5
Former-commit-id: 64fa9254b946eae7e61bbc3f513b7c3696c4f54f
2012-01-06 08:55:05 -06:00

377 lines
11 KiB
Python
Executable file

# Various useful small widgets
#
# Written by Konrad Hinsen <hinsen@cnrs-orleans.fr>
# Last revision: 2008-8-18
#
import Tkinter, Dialog, FileDialog
import copy, os, string
class FilenameEntry(Tkinter.Frame):
"""
Filename entry widget
A FilenameEntry widget consists of three parts: an identifying
label, a text entry field for the filename, and a button labelled
'browse' which call a file selection dialog box for picking a file
name.
"""
def __init__(self, master, text, pattern = '*', must_exist = True,
**attr):
"""
@param master: the parent widget
@param text: the label in front of the filename box
@type text: C{str}
@param pattern: the filename matching pattern that determines the
file list in the file selection dialog
@type pattern: C{str}
@param must_exist: if C{True}, allow only names of existing files
@type must_exist: C{bool}
"""
self.pattern = pattern
self.must_exist = must_exist
newattr = copy.copy(attr)
newattr['text'] = text
Tkinter.Frame.__init__(self, master)
apply(Tkinter.Label, (self,), newattr).pack(side=Tkinter.LEFT)
self.filename = Tkinter.StringVar()
Tkinter.Button(self, text="Browse...",
command=self.browse).pack(side=Tkinter.RIGHT)
newattr = copy.copy(attr)
newattr['textvariable'] = self.filename
entry = apply(Tkinter.Entry, (self,), newattr)
entry.pack(side=Tkinter.RIGHT, expand=1, fill=Tkinter.X)
entry.icursor("end")
def browse(self):
if self.must_exist:
file = FileDialog.LoadFileDialog(self).go(pattern=self.pattern)
else:
file = FileDialog.SaveFileDialog(self).go(pattern=self.pattern)
if file:
self.filename.set(file)
def get(self):
"""
@returns: the current filename
@rtype: C{str}
@raises ValueError: if must_exist is C{True} and the name does not
refer to an existing file
"""
filename = self.filename.get()
if self.must_exist and not os.path.exists(filename):
Dialog.Dialog(self, title='File not found',
text='The file "' + filename + '" does not exist.',
bitmap='warning', default=0,
strings = ('Cancel',))
raise ValueError
return filename
class FloatEntry(Tkinter.Frame):
"""
Entry field for float numbers
A FloatEntry widget consists of a label followed by a text entry
field.
"""
def __init__(self, master, text, init = None, lower=None, upper=None,
name = None, **attr):
"""
@param master: the parent widget
@param text: the label in front of the entry field
@type text: C{str}
@param init: an optional initial value (default: blank field)
@type init: number
@param upper: an optional upper limit for the value
@type upper: number
@param lower: an optional lower limit for the value
@type lower: number
"""
self.text = text
self.lower = lower
self.upper = upper
if name is None:
name = text
self.name = name
newattr = copy.copy(attr)
newattr['text'] = text
Tkinter.Frame.__init__(self, master)
apply(Tkinter.Label, (self,), newattr).pack(side=Tkinter.LEFT)
self.value = Tkinter.DoubleVar()
if init is not None:
self.value.set(init)
newattr = copy.copy(attr)
newattr['textvariable'] = self.value
self.entry = apply(Tkinter.Entry, (self,), newattr)
self.entry.pack(side=Tkinter.RIGHT, anchor=Tkinter.E,
expand=1, fill=Tkinter.X)
self.entry.icursor("end")
def bind(self, sequence=None, func=None, add=None):
self.entry.bind(sequence, func, add)
def set(self, value):
"""
Set the value displayed in the field
@param value: the new value
@type value: C{float}
"""
return self.value.set(value)
def get(self):
"""
@returns: the current value displayed in the field
@rtype: C{float}
@raises ValueError: if the current value is not a valid
number or is not within the specified limits
"""
try:
value = self.value.get()
except (Tkinter.TclError, ValueError):
Dialog.Dialog(self, title='Illegal value',
text='The value of "' + self.name +
'" must be a number.',
bitmap='warning', default=0,
strings = ('Cancel',))
raise ValueError
range_check = 0
if self.lower is not None and value < self.lower:
range_check = -1
if self.upper is not None and value > self.upper:
range_check = 1
if range_check != 0:
text = 'The value of "' + self.name + '" must not be '
if range_check < 0:
text = text + 'smaller than ' + `self.lower` + '.'
else:
text = text + 'larger than ' + `self.upper` + '.'
Dialog.Dialog(self, title='Value out of range', text=text,
bitmap='warning', default=0,
strings = ('Cancel',))
raise ValueError
return value
class IntEntry(FloatEntry):
"""
Entry field for integer numbers
A IntEntry widget consists of a label followed by a text entry
field.
"""
def get(self):
"""
@returns: the current value displayed in the field
@rtype: C{int}
@raises ValueError: if the current value is not a valid
number or is not within the specified limits
"""
value = FloatEntry.get(self)
ivalue = int(value)
if ivalue != value:
Dialog.Dialog(self, title='Illegal value',
text='The value of "' + self.name +
'" must be an integer.',
bitmap='warning', default=0,
strings = ('Cancel',))
raise ValueError
return ivalue
class ButtonBar(Tkinter.Frame):
"""
Horizontal array of buttons
"""
def __init__(self, master, left_button_list, right_button_list):
"""
@param master: the parent widget
@param left_button_list: a list of (text, action) tuples specifying the
buttons on the left-hand side of the button bar
@param right_button_list: a list of (text, action) tuples specifying the
buttons on the right-hand side of the button
bar
"""
Tkinter.Frame.__init__(self, master, bd=2, relief=Tkinter.SUNKEN)
for button, action in left_button_list:
Tkinter.Button(self, text=button,
command=action).pack(side=Tkinter.LEFT)
for button, action in right_button_list:
Tkinter.Button(self, text=button,
command=action).pack(side=Tkinter.RIGHT)
class StatusBar(Tkinter.Frame):
"""
Status bar
A status bar can be used to inform the user about the status of an
ongoing calculation. A message can be displayed with set() and
removed with clear(). In both cases, the StatusBar object makes
sure that the change takes place immediately. While a message
is being displayed, the cursor form is changed to a watch.
"""
def __init__(self, master):
"""
@param master: the parent widget
"""
Tkinter.Frame.__init__(self, master, bd=2, relief=Tkinter.RAISED)
self.text = Tkinter.Label(self, text='')
self.text.pack(side=Tkinter.LEFT, expand=Tkinter.YES)
def set(self, text):
"""
Set a message to be displayed in the status bar
@param text: the text of the message
"""
self.text.configure(text = text)
self.text.update_idletasks()
self.master.configure(cursor='watch')
self.update()
self.update_idletasks()
def clear(self):
"""
Clear any message displayed in the status bar
"""
self.text.configure(text = '')
self.text.update_idletasks()
self.master.configure(cursor='top_left_arrow')
self.update_idletasks()
#
# The following class was taken from the Pythonware Tkinter introduction
#
class ModalDialog(Tkinter.Toplevel):
def __init__(self, parent, title = None):
Tkinter.Toplevel.__init__(self, parent)
self.transient(parent)
if title:
self.title(title)
self.parent = parent
self.result = None
body = Tkinter.Frame(self)
self.initial_focus = self.body(body)
body.pack(padx=5, pady=5)
self.buttonbox()
self.grab_set()
if not self.initial_focus:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
parent.winfo_rooty()+50))
self.initial_focus.focus_set()
self.wait_window(self)
#
# construction hooks
def body(self, master):
# create dialog body. return widget that should have
# initial focus. this method should be overridden
pass
def buttonbox(self):
# add standard button box. override if you don't want the
# standard buttons
box = Tkinter.Frame(self)
w = Tkinter.Button(box, text="OK", width=10,
command=self.ok, default=Tkinter.ACTIVE)
w.pack(side=Tkinter.LEFT, padx=5, pady=5)
w = Tkinter.Button(box, text="Cancel", width=10, command=self.cancel)
w.pack(side=Tkinter.LEFT, padx=5, pady=5)
self.bind("<Return>", self.ok)
self.bind("<Escape>", self.cancel)
box.pack()
#
# standard button semantics
def ok(self, event=None):
if not self.validate():
self.initial_focus.focus_set() # put focus back
return
self.withdraw()
self.update_idletasks()
self.apply()
self.cancel()
def cancel(self, event=None):
# put focus back to the parent window
self.parent.focus_set()
self.destroy()
#
# command hooks
def validate(self):
return 1 # override
def apply(self):
pass # override
if __name__ == '__main__':
class MyDialog(ModalDialog):
def body(self, master):
Tkinter.Label(master, text="First:").grid(row=0)
Tkinter.Label(master, text="Second:").grid(row=1)
self.e1 = IntEntry(master, '', 0, 0, 10, fg='red')
self.e2 = Tkinter.Entry(master)
self.e1.grid(row=0, column=1)
self.e2.grid(row=1, column=1)
return self.e1 # initial focus
def apply(self):
first = string.atoi(self.e1.get())
second = string.atoi(self.e2.get())
self.result = first, second
root = Tkinter.Tk()
Tkinter.Button(root, text="Hello!").pack()
root.update()
d = MyDialog(root)
print d.result