Kaydet (Commit) 33cece05 authored tarafından Georg Brandl's avatar Georg Brandl

Tkinter renaming reversal: move modules back in their place.

üst 248e3a8b
# dialog.py -- Tkinter interface to the tk_dialog script.
from tkinter import *
from tkinter import _cnfmerge
if TkVersion <= 3.6:
DIALOG_ICON = 'warning'
else:
DIALOG_ICON = 'questhead'
class Dialog(Widget):
def __init__(self, master=None, cnf={}, **kw):
cnf = _cnfmerge((cnf, kw))
self.widgetName = '__dialog__'
Widget._setup(self, master, cnf)
self.num = self.tk.getint(
self.tk.call(
'tk_dialog', self._w,
cnf['title'], cnf['text'],
cnf['bitmap'], cnf['default'],
*cnf['strings']))
try: Widget.destroy(self)
except TclError: pass
def destroy(self): pass
def _test():
d = Dialog(None, {'title': 'File Modified',
'text':
'File "Python.h" has been modified'
' since the last time it was saved.'
' Do you want to save it before'
' exiting the application.',
'bitmap': DIALOG_ICON,
'default': 0,
'strings': ('Save File',
'Discard Changes',
'Return to Editor')})
print d.num
if __name__ == '__main__':
t = Button(None, {'text': 'Test',
'command': _test,
Pack: {}})
q = Button(None, {'text': 'Quit',
'command': t.quit,
Pack: {}})
t.mainloop()
"""File selection dialog classes.
Classes:
- FileDialog
- LoadFileDialog
- SaveFileDialog
"""
from Tkinter import *
from Dialog import Dialog
import os
import fnmatch
dialogstates = {}
class FileDialog:
"""Standard file selection dialog -- no checks on selected file.
Usage:
d = FileDialog(master)
fname = d.go(dir_or_file, pattern, default, key)
if fname is None: ...canceled...
else: ...open file...
All arguments to go() are optional.
The 'key' argument specifies a key in the global dictionary
'dialogstates', which keeps track of the values for the directory
and pattern arguments, overriding the values passed in (it does
not keep track of the default argument!). If no key is specified,
the dialog keeps no memory of previous state. Note that memory is
kept even when the dialog is canceled. (All this emulates the
behavior of the Macintosh file selection dialogs.)
"""
title = "File Selection Dialog"
def __init__(self, master, title=None):
if title is None: title = self.title
self.master = master
self.directory = None
self.top = Toplevel(master)
self.top.title(title)
self.top.iconname(title)
self.botframe = Frame(self.top)
self.botframe.pack(side=BOTTOM, fill=X)
self.selection = Entry(self.top)
self.selection.pack(side=BOTTOM, fill=X)
self.selection.bind('<Return>', self.ok_event)
self.filter = Entry(self.top)
self.filter.pack(side=TOP, fill=X)
self.filter.bind('<Return>', self.filter_command)
self.midframe = Frame(self.top)
self.midframe.pack(expand=YES, fill=BOTH)
self.filesbar = Scrollbar(self.midframe)
self.filesbar.pack(side=RIGHT, fill=Y)
self.files = Listbox(self.midframe, exportselection=0,
yscrollcommand=(self.filesbar, 'set'))
self.files.pack(side=RIGHT, expand=YES, fill=BOTH)
btags = self.files.bindtags()
self.files.bindtags(btags[1:] + btags[:1])
self.files.bind('<ButtonRelease-1>', self.files_select_event)
self.files.bind('<Double-ButtonRelease-1>', self.files_double_event)
self.filesbar.config(command=(self.files, 'yview'))
self.dirsbar = Scrollbar(self.midframe)
self.dirsbar.pack(side=LEFT, fill=Y)
self.dirs = Listbox(self.midframe, exportselection=0,
yscrollcommand=(self.dirsbar, 'set'))
self.dirs.pack(side=LEFT, expand=YES, fill=BOTH)
self.dirsbar.config(command=(self.dirs, 'yview'))
btags = self.dirs.bindtags()
self.dirs.bindtags(btags[1:] + btags[:1])
self.dirs.bind('<ButtonRelease-1>', self.dirs_select_event)
self.dirs.bind('<Double-ButtonRelease-1>', self.dirs_double_event)
self.ok_button = Button(self.botframe,
text="OK",
command=self.ok_command)
self.ok_button.pack(side=LEFT)
self.filter_button = Button(self.botframe,
text="Filter",
command=self.filter_command)
self.filter_button.pack(side=LEFT, expand=YES)
self.cancel_button = Button(self.botframe,
text="Cancel",
command=self.cancel_command)
self.cancel_button.pack(side=RIGHT)
self.top.protocol('WM_DELETE_WINDOW', self.cancel_command)
# XXX Are the following okay for a general audience?
self.top.bind('<Alt-w>', self.cancel_command)
self.top.bind('<Alt-W>', self.cancel_command)
def go(self, dir_or_file=os.curdir, pattern="*", default="", key=None):
if key and dialogstates.has_key(key):
self.directory, pattern = dialogstates[key]
else:
dir_or_file = os.path.expanduser(dir_or_file)
if os.path.isdir(dir_or_file):
self.directory = dir_or_file
else:
self.directory, default = os.path.split(dir_or_file)
self.set_filter(self.directory, pattern)
self.set_selection(default)
self.filter_command()
self.selection.focus_set()
self.top.wait_visibility() # window needs to be visible for the grab
self.top.grab_set()
self.how = None
self.master.mainloop() # Exited by self.quit(how)
if key:
directory, pattern = self.get_filter()
if self.how:
directory = os.path.dirname(self.how)
dialogstates[key] = directory, pattern
self.top.destroy()
return self.how
def quit(self, how=None):
self.how = how
self.master.quit() # Exit mainloop()
def dirs_double_event(self, event):
self.filter_command()
def dirs_select_event(self, event):
dir, pat = self.get_filter()
subdir = self.dirs.get('active')
dir = os.path.normpath(os.path.join(self.directory, subdir))
self.set_filter(dir, pat)
def files_double_event(self, event):
self.ok_command()
def files_select_event(self, event):
file = self.files.get('active')
self.set_selection(file)
def ok_event(self, event):
self.ok_command()
def ok_command(self):
self.quit(self.get_selection())
def filter_command(self, event=None):
dir, pat = self.get_filter()
try:
names = os.listdir(dir)
except os.error:
self.master.bell()
return
self.directory = dir
self.set_filter(dir, pat)
names.sort()
subdirs = [os.pardir]
matchingfiles = []
for name in names:
fullname = os.path.join(dir, name)
if os.path.isdir(fullname):
subdirs.append(name)
elif fnmatch.fnmatch(name, pat):
matchingfiles.append(name)
self.dirs.delete(0, END)
for name in subdirs:
self.dirs.insert(END, name)
self.files.delete(0, END)
for name in matchingfiles:
self.files.insert(END, name)
head, tail = os.path.split(self.get_selection())
if tail == os.curdir: tail = ''
self.set_selection(tail)
def get_filter(self):
filter = self.filter.get()
filter = os.path.expanduser(filter)
if filter[-1:] == os.sep or os.path.isdir(filter):
filter = os.path.join(filter, "*")
return os.path.split(filter)
def get_selection(self):
file = self.selection.get()
file = os.path.expanduser(file)
return file
def cancel_command(self, event=None):
self.quit()
def set_filter(self, dir, pat):
if not os.path.isabs(dir):
try:
pwd = os.getcwd()
except os.error:
pwd = None
if pwd:
dir = os.path.join(pwd, dir)
dir = os.path.normpath(dir)
self.filter.delete(0, END)
self.filter.insert(END, os.path.join(dir or os.curdir, pat or "*"))
def set_selection(self, file):
self.selection.delete(0, END)
self.selection.insert(END, os.path.join(self.directory, file))
class LoadFileDialog(FileDialog):
"""File selection dialog which checks that the file exists."""
title = "Load File Selection Dialog"
def ok_command(self):
file = self.get_selection()
if not os.path.isfile(file):
self.master.bell()
else:
self.quit(file)
class SaveFileDialog(FileDialog):
"""File selection dialog which checks that the file may be created."""
title = "Save File Selection Dialog"
def ok_command(self):
file = self.get_selection()
if os.path.exists(file):
if os.path.isdir(file):
self.master.bell()
return
d = Dialog(self.top,
title="Overwrite Existing File Question",
text="Overwrite existing file %r?" % (file,),
bitmap='questhead',
default=1,
strings=("Yes", "Cancel"))
if d.num != 0:
return
else:
head, tail = os.path.split(file)
if not os.path.isdir(head):
self.master.bell()
return
self.quit(file)
def test():
"""Simple test program."""
root = Tk()
root.withdraw()
fd = LoadFileDialog(root)
loadfile = fd.go(key="test")
fd = SaveFileDialog(root)
savefile = fd.go(key="test")
print loadfile, savefile
if __name__ == '__main__':
test()
import sys, os
# Delay import _tkinter until we have set TCL_LIBRARY,
# so that Tcl_FindExecutable has a chance to locate its
# encoding directory.
# Unfortunately, we cannot know the TCL_LIBRARY directory
# if we don't know the tcl version, which we cannot find out
# without import Tcl. Fortunately, Tcl will itself look in
# <TCL_LIBRARY>\..\tcl<TCL_VERSION>, so anything close to
# the real Tcl library will do.
prefix = os.path.join(sys.prefix,"tcl")
if not os.path.exists(prefix):
# devdir/../tcltk/lib
prefix = os.path.join(sys.prefix, os.path.pardir, "tcltk", "lib")
prefix = os.path.abspath(prefix)
# if this does not exist, no further search is needed
if os.path.exists(prefix):
if not os.environ.has_key("TCL_LIBRARY"):
for name in os.listdir(prefix):
if name.startswith("tcl"):
tcldir = os.path.join(prefix,name)
if os.path.isdir(tcldir):
os.environ["TCL_LIBRARY"] = tcldir
# Compute TK_LIBRARY, knowing that it has the same version
# as Tcl
import _tkinter
ver = str(_tkinter.TCL_VERSION)
if not os.environ.has_key("TK_LIBRARY"):
v = os.path.join(prefix, 'tk'+ver)
if os.path.exists(os.path.join(v, "tclIndex")):
os.environ['TK_LIBRARY'] = v
# We don't know the Tix version, so we must search the entire
# directory
if not os.environ.has_key("TIX_LIBRARY"):
for name in os.listdir(prefix):
if name.startswith("tix"):
tixdir = os.path.join(prefix,name)
if os.path.isdir(tixdir):
os.environ["TIX_LIBRARY"] = tixdir
# A ScrolledText widget feels like a text widget but also has a
# vertical scroll bar on its right. (Later, options may be added to
# add a horizontal bar as well, to make the bars disappear
# automatically when not needed, to move them to the other side of the
# window, etc.)
#
# Configuration options are passed to the Text widget.
# A Frame widget is inserted between the master and the text, to hold
# the Scrollbar widget.
# Most methods calls are inherited from the Text widget; Pack methods
# are redirected to the Frame widget however.
from tkinter import *
from tkinter import _cnfmerge
class ScrolledText(Text):
def __init__(self, master=None, cnf=None, **kw):
if cnf is None:
cnf = {}
if kw:
cnf = _cnfmerge((cnf, kw))
fcnf = {}
for k in cnf.keys():
if type(k) == ClassType or k == 'name':
fcnf[k] = cnf[k]
del cnf[k]
self.frame = Frame(master, **fcnf)
self.vbar = Scrollbar(self.frame, name='vbar')
self.vbar.pack(side=RIGHT, fill=Y)
cnf['name'] = 'text'
Text.__init__(self, self.frame, **cnf)
self.pack(side=LEFT, fill=BOTH, expand=1)
self['yscrollcommand'] = self.vbar.set
self.vbar['command'] = self.yview
# Copy geometry methods of self.frame -- hack!
methods = Pack.__dict__.keys()
methods = methods + Grid.__dict__.keys()
methods = methods + Place.__dict__.keys()
for m in methods:
if m[0] != '_' and m != 'config' and m != 'configure':
setattr(self, m, getattr(self.frame, m))
"""A simple but flexible modal dialog box."""
from Tkinter import *
class SimpleDialog:
def __init__(self, master,
text='', buttons=[], default=None, cancel=None,
title=None, class_=None):
if class_:
self.root = Toplevel(master, class_=class_)
else:
self.root = Toplevel(master)
if title:
self.root.title(title)
self.root.iconname(title)
self.message = Message(self.root, text=text, aspect=400)
self.message.pack(expand=1, fill=BOTH)
self.frame = Frame(self.root)
self.frame.pack()
self.num = default
self.cancel = cancel
self.default = default
self.root.bind('<Return>', self.return_event)
for num in range(len(buttons)):
s = buttons[num]
b = Button(self.frame, text=s,
command=(lambda self=self, num=num: self.done(num)))
if num == default:
b.config(relief=RIDGE, borderwidth=8)
b.pack(side=LEFT, fill=BOTH, expand=1)
self.root.protocol('WM_DELETE_WINDOW', self.wm_delete_window)
self._set_transient(master)
def _set_transient(self, master, relx=0.5, rely=0.3):
widget = self.root
widget.withdraw() # Remain invisible while we figure out the geometry
widget.transient(master)
widget.update_idletasks() # Actualize geometry information
if master.winfo_ismapped():
m_width = master.winfo_width()
m_height = master.winfo_height()
m_x = master.winfo_rootx()
m_y = master.winfo_rooty()
else:
m_width = master.winfo_screenwidth()
m_height = master.winfo_screenheight()
m_x = m_y = 0
w_width = widget.winfo_reqwidth()
w_height = widget.winfo_reqheight()
x = m_x + (m_width - w_width) * relx
y = m_y + (m_height - w_height) * rely
if x+w_width > master.winfo_screenwidth():
x = master.winfo_screenwidth() - w_width
elif x < 0:
x = 0
if y+w_height > master.winfo_screenheight():
y = master.winfo_screenheight() - w_height
elif y < 0:
y = 0
widget.geometry("+%d+%d" % (x, y))
widget.deiconify() # Become visible at the desired location
def go(self):
self.root.wait_visibility()
self.root.grab_set()
self.root.mainloop()
self.root.destroy()
return self.num
def return_event(self, event):
if self.default is None:
self.root.bell()
else:
self.done(self.default)
def wm_delete_window(self):
if self.cancel is None:
self.root.bell()
else:
self.done(self.cancel)
def done(self, num):
self.num = num
self.root.quit()
if __name__ == '__main__':
def test():
root = Tk()
def doit(root=root):
d = SimpleDialog(root,
text="This is a test dialog. "
"Would this have been an actual dialog, "
"the buttons below would have been glowing "
"in soft pink light.\n"
"Do you believe this?",
buttons=["Yes", "No", "Cancel"],
default=0,
cancel=2,
title="Test Dialog")
print d.go()
t = Button(root, text='Test', command=doit)
t.pack()
q = Button(root, text='Quit', command=t.quit)
q.pack()
t.mainloop()
test()
# -*-mode: python; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
#
# $Id$
#
# Tix.py -- Tix widget wrappers.
#
# For Tix, see http://tix.sourceforge.net
#
# - Sudhir Shenoy (sshenoy@gol.com), Dec. 1995.
# based on an idea of Jean-Marc Lugrin (lugrin@ms.com)
#
# NOTE: In order to minimize changes to Tkinter.py, some of the code here
# (TixWidget.__init__) has been taken from Tkinter (Widget.__init__)
# and will break if there are major changes in Tkinter.
#
# The Tix widgets are represented by a class hierarchy in python with proper
# inheritance of base classes.
#
# As a result after creating a 'w = StdButtonBox', I can write
# w.ok['text'] = 'Who Cares'
# or w.ok['bg'] = w['bg']
# or even w.ok.invoke()
# etc.
#
# Compare the demo tixwidgets.py to the original Tcl program and you will
# appreciate the advantages.
#
from tkinter import *
from tkinter import _flatten, _cnfmerge, _default_root
# WARNING - TkVersion is a limited precision floating point number
if TkVersion < 3.999:
raise ImportError, "This version of Tix.py requires Tk 4.0 or higher"
import _tkinter # If this fails your Python may not be configured for Tk
# Some more constants (for consistency with Tkinter)
WINDOW = 'window'
TEXT = 'text'
STATUS = 'status'
IMMEDIATE = 'immediate'
IMAGE = 'image'
IMAGETEXT = 'imagetext'
BALLOON = 'balloon'
AUTO = 'auto'
ACROSSTOP = 'acrosstop'
# Some constants used by Tkinter dooneevent()
TCL_DONT_WAIT = 1 << 1
TCL_WINDOW_EVENTS = 1 << 2
TCL_FILE_EVENTS = 1 << 3
TCL_TIMER_EVENTS = 1 << 4
TCL_IDLE_EVENTS = 1 << 5
TCL_ALL_EVENTS = 0
# BEWARE - this is implemented by copying some code from the Widget class
# in Tkinter (to override Widget initialization) and is therefore
# liable to break.
import tkinter, os
# Could probably add this to Tkinter.Misc
class tixCommand:
"""The tix commands provide access to miscellaneous elements
of Tix's internal state and the Tix application context.
Most of the information manipulated by these commands pertains
to the application as a whole, or to a screen or
display, rather than to a particular window.
This is a mixin class, assumed to be mixed to Tkinter.Tk
that supports the self.tk.call method.
"""
def tix_addbitmapdir(self, directory):
"""Tix maintains a list of directories under which
the tix_getimage and tix_getbitmap commands will
search for image files. The standard bitmap directory
is $TIX_LIBRARY/bitmaps. The addbitmapdir command
adds directory into this list. By using this
command, the image files of an applications can
also be located using the tix_getimage or tix_getbitmap
command.
"""
return self.tk.call('tix', 'addbitmapdir', directory)
def tix_cget(self, option):
"""Returns the current value of the configuration
option given by option. Option may be any of the
options described in the CONFIGURATION OPTIONS section.
"""
return self.tk.call('tix', 'cget', option)
def tix_configure(self, cnf=None, **kw):
"""Query or modify the configuration options of the Tix application
context. If no option is specified, returns a dictionary all of the
available options. If option is specified with no value, then the
command returns a list describing the one named option (this list
will be identical to the corresponding sublist of the value
returned if no option is specified). If one or more option-value
pairs are specified, then the command modifies the given option(s)
to have the given value(s); in this case the command returns an
empty string. Option may be any of the configuration options.
"""
# Copied from Tkinter.py
if kw:
cnf = _cnfmerge((cnf, kw))
elif cnf:
cnf = _cnfmerge(cnf)
if cnf is None:
cnf = {}
for x in self.tk.split(self.tk.call('tix', 'configure')):
cnf[x[0][1:]] = (x[0][1:],) + x[1:]
return cnf
if isinstance(cnf, StringType):
x = self.tk.split(self.tk.call('tix', 'configure', '-'+cnf))
return (x[0][1:],) + x[1:]
return self.tk.call(('tix', 'configure') + self._options(cnf))
def tix_filedialog(self, dlgclass=None):
"""Returns the file selection dialog that may be shared among
different calls from this application. This command will create a
file selection dialog widget when it is called the first time. This
dialog will be returned by all subsequent calls to tix_filedialog.
An optional dlgclass parameter can be passed to specified what type
of file selection dialog widget is desired. Possible options are
tix FileSelectDialog or tixExFileSelectDialog.
"""
if dlgclass is not None:
return self.tk.call('tix', 'filedialog', dlgclass)
else:
return self.tk.call('tix', 'filedialog')
def tix_getbitmap(self, name):
"""Locates a bitmap file of the name name.xpm or name in one of the
bitmap directories (see the tix_addbitmapdir command above). By
using tix_getbitmap, you can avoid hard coding the pathnames of the
bitmap files in your application. When successful, it returns the
complete pathname of the bitmap file, prefixed with the character
'@'. The returned value can be used to configure the -bitmap
option of the TK and Tix widgets.
"""
return self.tk.call('tix', 'getbitmap', name)
def tix_getimage(self, name):
"""Locates an image file of the name name.xpm, name.xbm or name.ppm
in one of the bitmap directories (see the addbitmapdir command
above). If more than one file with the same name (but different
extensions) exist, then the image type is chosen according to the
depth of the X display: xbm images are chosen on monochrome
displays and color images are chosen on color displays. By using
tix_ getimage, you can advoid hard coding the pathnames of the
image files in your application. When successful, this command
returns the name of the newly created image, which can be used to
configure the -image option of the Tk and Tix widgets.
"""
return self.tk.call('tix', 'getimage', name)
def tix_option_get(self, name):
"""Gets the options manitained by the Tix
scheme mechanism. Available options include:
active_bg active_fg bg
bold_font dark1_bg dark1_fg
dark2_bg dark2_fg disabled_fg
fg fixed_font font
inactive_bg inactive_fg input1_bg
input2_bg italic_font light1_bg
light1_fg light2_bg light2_fg
menu_font output1_bg output2_bg
select_bg select_fg selector
"""
# could use self.tk.globalgetvar('tixOption', name)
return self.tk.call('tix', 'option', 'get', name)
def tix_resetoptions(self, newScheme, newFontSet, newScmPrio=None):
"""Resets the scheme and fontset of the Tix application to
newScheme and newFontSet, respectively. This affects only those
widgets created after this call. Therefore, it is best to call the
resetoptions command before the creation of any widgets in a Tix
application.
The optional parameter newScmPrio can be given to reset the
priority level of the Tk options set by the Tix schemes.
Because of the way Tk handles the X option database, after Tix has
been has imported and inited, it is not possible to reset the color
schemes and font sets using the tix config command. Instead, the
tix_resetoptions command must be used.
"""
if newScmPrio is not None:
return self.tk.call('tix', 'resetoptions', newScheme, newFontSet, newScmPrio)
else:
return self.tk.call('tix', 'resetoptions', newScheme, newFontSet)
class Tk(tkinter.Tk, tixCommand):
"""Toplevel widget of Tix which represents mostly the main window
of an application. It has an associated Tcl interpreter."""
def __init__(self, screenName=None, baseName=None, className='Tix'):
tkinter.Tk.__init__(self, screenName, baseName, className)
tixlib = os.environ.get('TIX_LIBRARY')
self.tk.eval('global auto_path; lappend auto_path [file dir [info nameof]]')
if tixlib is not None:
self.tk.eval('global auto_path; lappend auto_path {%s}' % tixlib)
self.tk.eval('global tcl_pkgPath; lappend tcl_pkgPath {%s}' % tixlib)
# Load Tix - this should work dynamically or statically
# If it's static, tcl/tix8.1/pkgIndex.tcl should have
# 'load {} Tix'
# If it's dynamic under Unix, tcl/tix8.1/pkgIndex.tcl should have
# 'load libtix8.1.8.3.so Tix'
self.tk.eval('package require Tix')
def destroy(self):
# For safety, remove an delete_window binding before destroy
self.protocol("WM_DELETE_WINDOW", "")
tkinter.Tk.destroy(self)
# The Tix 'tixForm' geometry manager
class Form:
"""The Tix Form geometry manager
Widgets can be arranged by specifying attachments to other widgets.
See Tix documentation for complete details"""
def config(self, cnf={}, **kw):
self.tk.call('tixForm', self._w, *self._options(cnf, kw))
form = config
def __setitem__(self, key, value):
Form.form(self, {key: value})
def check(self):
return self.tk.call('tixForm', 'check', self._w)
def forget(self):
self.tk.call('tixForm', 'forget', self._w)
def grid(self, xsize=0, ysize=0):
if (not xsize) and (not ysize):
x = self.tk.call('tixForm', 'grid', self._w)
y = self.tk.splitlist(x)
z = ()
for x in y:
z = z + (self.tk.getint(x),)
return z
return self.tk.call('tixForm', 'grid', self._w, xsize, ysize)
def info(self, option=None):
if not option:
return self.tk.call('tixForm', 'info', self._w)
if option[0] != '-':
option = '-' + option
return self.tk.call('tixForm', 'info', self._w, option)
def slaves(self):
return map(self._nametowidget,
self.tk.splitlist(
self.tk.call(
'tixForm', 'slaves', self._w)))
tkinter.Widget.__bases__ = tkinter.Widget.__bases__ + (Form,)
class TixWidget(tkinter.Widget):
"""A TixWidget class is used to package all (or most) Tix widgets.
Widget initialization is extended in two ways:
1) It is possible to give a list of options which must be part of
the creation command (so called Tix 'static' options). These cannot be
given as a 'config' command later.
2) It is possible to give the name of an existing TK widget. These are
child widgets created automatically by a Tix mega-widget. The Tk call
to create these widgets is therefore bypassed in TixWidget.__init__
Both options are for use by subclasses only.
"""
def __init__ (self, master=None, widgetName=None,
static_options=None, cnf={}, kw={}):
# Merge keywords and dictionary arguments
if kw:
cnf = _cnfmerge((cnf, kw))
else:
cnf = _cnfmerge(cnf)
# Move static options into extra. static_options must be
# a list of keywords (or None).
extra=()
# 'options' is always a static option
if static_options:
static_options.append('options')
else:
static_options = ['options']
for k,v in cnf.items()[:]:
if k in static_options:
extra = extra + ('-' + k, v)
del cnf[k]
self.widgetName = widgetName
Widget._setup(self, master, cnf)
# If widgetName is None, this is a dummy creation call where the
# corresponding Tk widget has already been created by Tix
if widgetName:
self.tk.call(widgetName, self._w, *extra)
# Non-static options - to be done via a 'config' command
if cnf:
Widget.config(self, cnf)
# Dictionary to hold subwidget names for easier access. We can't
# use the children list because the public Tix names may not be the
# same as the pathname component
self.subwidget_list = {}
# We set up an attribute access function so that it is possible to
# do w.ok['text'] = 'Hello' rather than w.subwidget('ok')['text'] = 'Hello'
# when w is a StdButtonBox.
# We can even do w.ok.invoke() because w.ok is subclassed from the
# Button class if you go through the proper constructors
def __getattr__(self, name):
if self.subwidget_list.has_key(name):
return self.subwidget_list[name]
raise AttributeError, name
def set_silent(self, value):
"""Set a variable without calling its action routine"""
self.tk.call('tixSetSilent', self._w, value)
def subwidget(self, name):
"""Return the named subwidget (which must have been created by
the sub-class)."""
n = self._subwidget_name(name)
if not n:
raise TclError, "Subwidget " + name + " not child of " + self._name
# Remove header of name and leading dot
n = n[len(self._w)+1:]
return self._nametowidget(n)
def subwidgets_all(self):
"""Return all subwidgets."""
names = self._subwidget_names()
if not names:
return []
retlist = []
for name in names:
name = name[len(self._w)+1:]
try:
retlist.append(self._nametowidget(name))
except:
# some of the widgets are unknown e.g. border in LabelFrame
pass
return retlist
def _subwidget_name(self,name):
"""Get a subwidget name (returns a String, not a Widget !)"""
try:
return self.tk.call(self._w, 'subwidget', name)
except TclError:
return None
def _subwidget_names(self):
"""Return the name of all subwidgets."""
try:
x = self.tk.call(self._w, 'subwidgets', '-all')
return self.tk.split(x)
except TclError:
return None
def config_all(self, option, value):
"""Set configuration options for all subwidgets (and self)."""
if option == '':
return
elif not isinstance(option, StringType):
option = repr(option)
if not isinstance(value, StringType):
value = repr(value)
names = self._subwidget_names()
for name in names:
self.tk.call(name, 'configure', '-' + option, value)
# These are missing from Tkinter
def image_create(self, imgtype, cnf={}, master=None, **kw):
if not master:
master = tkinter._default_root
if not master:
raise RuntimeError, 'Too early to create image'
if kw and cnf: cnf = _cnfmerge((cnf, kw))
elif kw: cnf = kw
options = ()
for k, v in cnf.items():
if callable(v):
v = self._register(v)
options = options + ('-'+k, v)
return master.tk.call(('image', 'create', imgtype,) + options)
def image_delete(self, imgname):
try:
self.tk.call('image', 'delete', imgname)
except TclError:
# May happen if the root was destroyed
pass
# Subwidgets are child widgets created automatically by mega-widgets.
# In python, we have to create these subwidgets manually to mirror their
# existence in Tk/Tix.
class TixSubWidget(TixWidget):
"""Subwidget class.
This is used to mirror child widgets automatically created
by Tix/Tk as part of a mega-widget in Python (which is not informed
of this)"""
def __init__(self, master, name,
destroy_physically=1, check_intermediate=1):
if check_intermediate:
path = master._subwidget_name(name)
try:
path = path[len(master._w)+1:]
plist = path.split('.')
except:
plist = []
if not check_intermediate:
# immediate descendant
TixWidget.__init__(self, master, None, None, {'name' : name})
else:
# Ensure that the intermediate widgets exist
parent = master
for i in range(len(plist) - 1):
n = '.'.join(plist[:i+1])
try:
w = master._nametowidget(n)
parent = w
except KeyError:
# Create the intermediate widget
parent = TixSubWidget(parent, plist[i],
destroy_physically=0,
check_intermediate=0)
# The Tk widget name is in plist, not in name
if plist:
name = plist[-1]
TixWidget.__init__(self, parent, None, None, {'name' : name})
self.destroy_physically = destroy_physically
def destroy(self):
# For some widgets e.g., a NoteBook, when we call destructors,
# we must be careful not to destroy the frame widget since this
# also destroys the parent NoteBook thus leading to an exception
# in Tkinter when it finally calls Tcl to destroy the NoteBook
for c in self.children.values(): c.destroy()
if self.master.children.has_key(self._name):
del self.master.children[self._name]
if self.master.subwidget_list.has_key(self._name):
del self.master.subwidget_list[self._name]
if self.destroy_physically:
# This is bypassed only for a few widgets
self.tk.call('destroy', self._w)
# Useful func. to split Tcl lists and return as a dict. From Tkinter.py
def _lst2dict(lst):
dict = {}
for x in lst:
dict[x[0][1:]] = (x[0][1:],) + x[1:]
return dict
# Useful class to create a display style - later shared by many items.
# Contributed by Steffen Kremser
class DisplayStyle:
"""DisplayStyle - handle configuration options shared by
(multiple) Display Items"""
def __init__(self, itemtype, cnf={}, **kw):
master = _default_root # global from Tkinter
if not master and cnf.has_key('refwindow'): master=cnf['refwindow']
elif not master and kw.has_key('refwindow'): master= kw['refwindow']
elif not master: raise RuntimeError, "Too early to create display style: no root window"
self.tk = master.tk
self.stylename = self.tk.call('tixDisplayStyle', itemtype,
*self._options(cnf,kw) )
def __str__(self):
return self.stylename
def _options(self, cnf, kw):
if kw and cnf:
cnf = _cnfmerge((cnf, kw))
elif kw:
cnf = kw
opts = ()
for k, v in cnf.items():
opts = opts + ('-'+k, v)
return opts
def delete(self):
self.tk.call(self.stylename, 'delete')
def __setitem__(self,key,value):
self.tk.call(self.stylename, 'configure', '-%s'%key, value)
def config(self, cnf={}, **kw):
return _lst2dict(
self.tk.split(
self.tk.call(
self.stylename, 'configure', *self._options(cnf,kw))))
def __getitem__(self,key):
return self.tk.call(self.stylename, 'cget', '-%s'%key)
######################################################
### The Tix Widget classes - in alphabetical order ###
######################################################
class Balloon(TixWidget):
"""Balloon help widget.
Subwidget Class
--------- -----
label Label
message Message"""
# FIXME: It should inherit -superclass tixShell
def __init__(self, master=None, cnf={}, **kw):
# static seem to be -installcolormap -initwait -statusbar -cursor
static = ['options', 'installcolormap', 'initwait', 'statusbar',
'cursor']
TixWidget.__init__(self, master, 'tixBalloon', static, cnf, kw)
self.subwidget_list['label'] = _dummyLabel(self, 'label',
destroy_physically=0)
self.subwidget_list['message'] = _dummyLabel(self, 'message',
destroy_physically=0)
def bind_widget(self, widget, cnf={}, **kw):
"""Bind balloon widget to another.
One balloon widget may be bound to several widgets at the same time"""
self.tk.call(self._w, 'bind', widget._w, *self._options(cnf, kw))
def unbind_widget(self, widget):
self.tk.call(self._w, 'unbind', widget._w)
class ButtonBox(TixWidget):
"""ButtonBox - A container for pushbuttons.
Subwidgets are the buttons added with the add method.
"""
def __init__(self, master=None, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixButtonBox',
['orientation', 'options'], cnf, kw)
def add(self, name, cnf={}, **kw):
"""Add a button with given name to box."""
btn = self.tk.call(self._w, 'add', name, *self._options(cnf, kw))
self.subwidget_list[name] = _dummyButton(self, name)
return btn
def invoke(self, name):
if self.subwidget_list.has_key(name):
self.tk.call(self._w, 'invoke', name)
class ComboBox(TixWidget):
"""ComboBox - an Entry field with a dropdown menu. The user can select a
choice by either typing in the entry subwdget or selecting from the
listbox subwidget.
Subwidget Class
--------- -----
entry Entry
arrow Button
slistbox ScrolledListBox
tick Button
cross Button : present if created with the fancy option"""
# FIXME: It should inherit -superclass tixLabelWidget
def __init__ (self, master=None, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixComboBox',
['editable', 'dropdown', 'fancy', 'options'],
cnf, kw)
self.subwidget_list['label'] = _dummyLabel(self, 'label')
self.subwidget_list['entry'] = _dummyEntry(self, 'entry')
self.subwidget_list['arrow'] = _dummyButton(self, 'arrow')
self.subwidget_list['slistbox'] = _dummyScrolledListBox(self,
'slistbox')
try:
self.subwidget_list['tick'] = _dummyButton(self, 'tick')
self.subwidget_list['cross'] = _dummyButton(self, 'cross')
except TypeError:
# unavailable when -fancy not specified
pass
# align
def add_history(self, str):
self.tk.call(self._w, 'addhistory', str)
def append_history(self, str):
self.tk.call(self._w, 'appendhistory', str)
def insert(self, index, str):
self.tk.call(self._w, 'insert', index, str)
def pick(self, index):
self.tk.call(self._w, 'pick', index)
class Control(TixWidget):
"""Control - An entry field with value change arrows. The user can
adjust the value by pressing the two arrow buttons or by entering
the value directly into the entry. The new value will be checked
against the user-defined upper and lower limits.
Subwidget Class
--------- -----
incr Button
decr Button
entry Entry
label Label"""
# FIXME: It should inherit -superclass tixLabelWidget
def __init__ (self, master=None, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixControl', ['options'], cnf, kw)
self.subwidget_list['incr'] = _dummyButton(self, 'incr')
self.subwidget_list['decr'] = _dummyButton(self, 'decr')
self.subwidget_list['label'] = _dummyLabel(self, 'label')
self.subwidget_list['entry'] = _dummyEntry(self, 'entry')
def decrement(self):
self.tk.call(self._w, 'decr')
def increment(self):
self.tk.call(self._w, 'incr')
def invoke(self):
self.tk.call(self._w, 'invoke')
def update(self):
self.tk.call(self._w, 'update')
class DirList(TixWidget):
"""DirList - displays a list view of a directory, its previous
directories and its sub-directories. The user can choose one of
the directories displayed in the list or change to another directory.
Subwidget Class
--------- -----
hlist HList
hsb Scrollbar
vsb Scrollbar"""
# FIXME: It should inherit -superclass tixScrolledHList
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixDirList', ['options'], cnf, kw)
self.subwidget_list['hlist'] = _dummyHList(self, 'hlist')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
def chdir(self, dir):
self.tk.call(self._w, 'chdir', dir)
class DirTree(TixWidget):
"""DirTree - Directory Listing in a hierarchical view.
Displays a tree view of a directory, its previous directories and its
sub-directories. The user can choose one of the directories displayed
in the list or change to another directory.
Subwidget Class
--------- -----
hlist HList
hsb Scrollbar
vsb Scrollbar"""
# FIXME: It should inherit -superclass tixScrolledHList
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixDirTree', ['options'], cnf, kw)
self.subwidget_list['hlist'] = _dummyHList(self, 'hlist')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
def chdir(self, dir):
self.tk.call(self._w, 'chdir', dir)
class DirSelectBox(TixWidget):
"""DirSelectBox - Motif style file select box.
It is generally used for
the user to choose a file. FileSelectBox stores the files mostly
recently selected into a ComboBox widget so that they can be quickly
selected again.
Subwidget Class
--------- -----
selection ComboBox
filter ComboBox
dirlist ScrolledListBox
filelist ScrolledListBox"""
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixDirSelectBox', ['options'], cnf, kw)
self.subwidget_list['dirlist'] = _dummyDirList(self, 'dirlist')
self.subwidget_list['dircbx'] = _dummyFileComboBox(self, 'dircbx')
class ExFileSelectBox(TixWidget):
"""ExFileSelectBox - MS Windows style file select box.
It provides an convenient method for the user to select files.
Subwidget Class
--------- -----
cancel Button
ok Button
hidden Checkbutton
types ComboBox
dir ComboBox
file ComboBox
dirlist ScrolledListBox
filelist ScrolledListBox"""
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixExFileSelectBox', ['options'], cnf, kw)
self.subwidget_list['cancel'] = _dummyButton(self, 'cancel')
self.subwidget_list['ok'] = _dummyButton(self, 'ok')
self.subwidget_list['hidden'] = _dummyCheckbutton(self, 'hidden')
self.subwidget_list['types'] = _dummyComboBox(self, 'types')
self.subwidget_list['dir'] = _dummyComboBox(self, 'dir')
self.subwidget_list['dirlist'] = _dummyDirList(self, 'dirlist')
self.subwidget_list['file'] = _dummyComboBox(self, 'file')
self.subwidget_list['filelist'] = _dummyScrolledListBox(self, 'filelist')
def filter(self):
self.tk.call(self._w, 'filter')
def invoke(self):
self.tk.call(self._w, 'invoke')
# Should inherit from a Dialog class
class DirSelectDialog(TixWidget):
"""The DirSelectDialog widget presents the directories in the file
system in a dialog window. The user can use this dialog window to
navigate through the file system to select the desired directory.
Subwidgets Class
---------- -----
dirbox DirSelectDialog"""
# FIXME: It should inherit -superclass tixDialogShell
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixDirSelectDialog',
['options'], cnf, kw)
self.subwidget_list['dirbox'] = _dummyDirSelectBox(self, 'dirbox')
# cancel and ok buttons are missing
def popup(self):
self.tk.call(self._w, 'popup')
def popdown(self):
self.tk.call(self._w, 'popdown')
# Should inherit from a Dialog class
class ExFileSelectDialog(TixWidget):
"""ExFileSelectDialog - MS Windows style file select dialog.
It provides an convenient method for the user to select files.
Subwidgets Class
---------- -----
fsbox ExFileSelectBox"""
# FIXME: It should inherit -superclass tixDialogShell
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixExFileSelectDialog',
['options'], cnf, kw)
self.subwidget_list['fsbox'] = _dummyExFileSelectBox(self, 'fsbox')
def popup(self):
self.tk.call(self._w, 'popup')
def popdown(self):
self.tk.call(self._w, 'popdown')
class FileSelectBox(TixWidget):
"""ExFileSelectBox - Motif style file select box.
It is generally used for
the user to choose a file. FileSelectBox stores the files mostly
recently selected into a ComboBox widget so that they can be quickly
selected again.
Subwidget Class
--------- -----
selection ComboBox
filter ComboBox
dirlist ScrolledListBox
filelist ScrolledListBox"""
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixFileSelectBox', ['options'], cnf, kw)
self.subwidget_list['dirlist'] = _dummyScrolledListBox(self, 'dirlist')
self.subwidget_list['filelist'] = _dummyScrolledListBox(self, 'filelist')
self.subwidget_list['filter'] = _dummyComboBox(self, 'filter')
self.subwidget_list['selection'] = _dummyComboBox(self, 'selection')
def apply_filter(self): # name of subwidget is same as command
self.tk.call(self._w, 'filter')
def invoke(self):
self.tk.call(self._w, 'invoke')
# Should inherit from a Dialog class
class FileSelectDialog(TixWidget):
"""FileSelectDialog - Motif style file select dialog.
Subwidgets Class
---------- -----
btns StdButtonBox
fsbox FileSelectBox"""
# FIXME: It should inherit -superclass tixStdDialogShell
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixFileSelectDialog',
['options'], cnf, kw)
self.subwidget_list['btns'] = _dummyStdButtonBox(self, 'btns')
self.subwidget_list['fsbox'] = _dummyFileSelectBox(self, 'fsbox')
def popup(self):
self.tk.call(self._w, 'popup')
def popdown(self):
self.tk.call(self._w, 'popdown')
class FileEntry(TixWidget):
"""FileEntry - Entry field with button that invokes a FileSelectDialog.
The user can type in the filename manually. Alternatively, the user can
press the button widget that sits next to the entry, which will bring
up a file selection dialog.
Subwidgets Class
---------- -----
button Button
entry Entry"""
# FIXME: It should inherit -superclass tixLabelWidget
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixFileEntry',
['dialogtype', 'options'], cnf, kw)
self.subwidget_list['button'] = _dummyButton(self, 'button')
self.subwidget_list['entry'] = _dummyEntry(self, 'entry')
def invoke(self):
self.tk.call(self._w, 'invoke')
def file_dialog(self):
# FIXME: return python object
pass
class HList(TixWidget):
"""HList - Hierarchy display widget can be used to display any data
that have a hierarchical structure, for example, file system directory
trees. The list entries are indented and connected by branch lines
according to their places in the hierachy.
Subwidgets - None"""
def __init__ (self,master=None,cnf={}, **kw):
TixWidget.__init__(self, master, 'tixHList',
['columns', 'options'], cnf, kw)
def add(self, entry, cnf={}, **kw):
return self.tk.call(self._w, 'add', entry, *self._options(cnf, kw))
def add_child(self, parent=None, cnf={}, **kw):
if not parent:
parent = ''
return self.tk.call(
self._w, 'addchild', parent, *self._options(cnf, kw))
def anchor_set(self, entry):
self.tk.call(self._w, 'anchor', 'set', entry)
def anchor_clear(self):
self.tk.call(self._w, 'anchor', 'clear')
def column_width(self, col=0, width=None, chars=None):
if not chars:
return self.tk.call(self._w, 'column', 'width', col, width)
else:
return self.tk.call(self._w, 'column', 'width', col,
'-char', chars)
def delete_all(self):
self.tk.call(self._w, 'delete', 'all')
def delete_entry(self, entry):
self.tk.call(self._w, 'delete', 'entry', entry)
def delete_offsprings(self, entry):
self.tk.call(self._w, 'delete', 'offsprings', entry)
def delete_siblings(self, entry):
self.tk.call(self._w, 'delete', 'siblings', entry)
def dragsite_set(self, index):
self.tk.call(self._w, 'dragsite', 'set', index)
def dragsite_clear(self):
self.tk.call(self._w, 'dragsite', 'clear')
def dropsite_set(self, index):
self.tk.call(self._w, 'dropsite', 'set', index)
def dropsite_clear(self):
self.tk.call(self._w, 'dropsite', 'clear')
def header_create(self, col, cnf={}, **kw):
self.tk.call(self._w, 'header', 'create', col, *self._options(cnf, kw))
def header_configure(self, col, cnf={}, **kw):
if cnf is None:
return _lst2dict(
self.tk.split(
self.tk.call(self._w, 'header', 'configure', col)))
self.tk.call(self._w, 'header', 'configure', col,
*self._options(cnf, kw))
def header_cget(self, col, opt):
return self.tk.call(self._w, 'header', 'cget', col, opt)
def header_exists(self, col):
return self.tk.call(self._w, 'header', 'exists', col)
def header_delete(self, col):
self.tk.call(self._w, 'header', 'delete', col)
def header_size(self, col):
return self.tk.call(self._w, 'header', 'size', col)
def hide_entry(self, entry):
self.tk.call(self._w, 'hide', 'entry', entry)
def indicator_create(self, entry, cnf={}, **kw):
self.tk.call(
self._w, 'indicator', 'create', entry, *self._options(cnf, kw))
def indicator_configure(self, entry, cnf={}, **kw):
if cnf is None:
return _lst2dict(
self.tk.split(
self.tk.call(self._w, 'indicator', 'configure', entry)))
self.tk.call(
self._w, 'indicator', 'configure', entry, *self._options(cnf, kw))
def indicator_cget(self, entry, opt):
return self.tk.call(self._w, 'indicator', 'cget', entry, opt)
def indicator_exists(self, entry):
return self.tk.call (self._w, 'indicator', 'exists', entry)
def indicator_delete(self, entry):
self.tk.call(self._w, 'indicator', 'delete', entry)
def indicator_size(self, entry):
return self.tk.call(self._w, 'indicator', 'size', entry)
def info_anchor(self):
return self.tk.call(self._w, 'info', 'anchor')
def info_children(self, entry=None):
c = self.tk.call(self._w, 'info', 'children', entry)
return self.tk.splitlist(c)
def info_data(self, entry):
return self.tk.call(self._w, 'info', 'data', entry)
def info_exists(self, entry):
return self.tk.call(self._w, 'info', 'exists', entry)
def info_hidden(self, entry):
return self.tk.call(self._w, 'info', 'hidden', entry)
def info_next(self, entry):
return self.tk.call(self._w, 'info', 'next', entry)
def info_parent(self, entry):
return self.tk.call(self._w, 'info', 'parent', entry)
def info_prev(self, entry):
return self.tk.call(self._w, 'info', 'prev', entry)
def info_selection(self):
c = self.tk.call(self._w, 'info', 'selection')
return self.tk.splitlist(c)
def item_cget(self, entry, col, opt):
return self.tk.call(self._w, 'item', 'cget', entry, col, opt)
def item_configure(self, entry, col, cnf={}, **kw):
if cnf is None:
return _lst2dict(
self.tk.split(
self.tk.call(self._w, 'item', 'configure', entry, col)))
self.tk.call(self._w, 'item', 'configure', entry, col,
*self._options(cnf, kw))
def item_create(self, entry, col, cnf={}, **kw):
self.tk.call(
self._w, 'item', 'create', entry, col, *self._options(cnf, kw))
def item_exists(self, entry, col):
return self.tk.call(self._w, 'item', 'exists', entry, col)
def item_delete(self, entry, col):
self.tk.call(self._w, 'item', 'delete', entry, col)
def entrycget(self, entry, opt):
return self.tk.call(self._w, 'entrycget', entry, opt)
def entryconfigure(self, entry, cnf={}, **kw):
if cnf is None:
return _lst2dict(
self.tk.split(
self.tk.call(self._w, 'entryconfigure', entry)))
self.tk.call(self._w, 'entryconfigure', entry,
*self._options(cnf, kw))
def nearest(self, y):
return self.tk.call(self._w, 'nearest', y)
def see(self, entry):
self.tk.call(self._w, 'see', entry)
def selection_clear(self, cnf={}, **kw):
self.tk.call(self._w, 'selection', 'clear', *self._options(cnf, kw))
def selection_includes(self, entry):
return self.tk.call(self._w, 'selection', 'includes', entry)
def selection_set(self, first, last=None):
self.tk.call(self._w, 'selection', 'set', first, last)
def show_entry(self, entry):
return self.tk.call(self._w, 'show', 'entry', entry)
def xview(self, *args):
self.tk.call(self._w, 'xview', *args)
def yview(self, *args):
self.tk.call(self._w, 'yview', *args)
class InputOnly(TixWidget):
"""InputOnly - Invisible widget. Unix only.
Subwidgets - None"""
def __init__ (self,master=None,cnf={}, **kw):
TixWidget.__init__(self, master, 'tixInputOnly', None, cnf, kw)
class LabelEntry(TixWidget):
"""LabelEntry - Entry field with label. Packages an entry widget
and a label into one mega widget. It can beused be used to simplify
the creation of ``entry-form'' type of interface.
Subwidgets Class
---------- -----
label Label
entry Entry"""
def __init__ (self,master=None,cnf={}, **kw):
TixWidget.__init__(self, master, 'tixLabelEntry',
['labelside','options'], cnf, kw)
self.subwidget_list['label'] = _dummyLabel(self, 'label')
self.subwidget_list['entry'] = _dummyEntry(self, 'entry')
class LabelFrame(TixWidget):
"""LabelFrame - Labelled Frame container. Packages a frame widget
and a label into one mega widget. To create widgets inside a
LabelFrame widget, one creates the new widgets relative to the
frame subwidget and manage them inside the frame subwidget.
Subwidgets Class
---------- -----
label Label
frame Frame"""
def __init__ (self,master=None,cnf={}, **kw):
TixWidget.__init__(self, master, 'tixLabelFrame',
['labelside','options'], cnf, kw)
self.subwidget_list['label'] = _dummyLabel(self, 'label')
self.subwidget_list['frame'] = _dummyFrame(self, 'frame')
class ListNoteBook(TixWidget):
"""A ListNoteBook widget is very similar to the TixNoteBook widget:
it can be used to display many windows in a limited space using a
notebook metaphor. The notebook is divided into a stack of pages
(windows). At one time only one of these pages can be shown.
The user can navigate through these pages by
choosing the name of the desired page in the hlist subwidget."""
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixListNoteBook', ['options'], cnf, kw)
# Is this necessary? It's not an exposed subwidget in Tix.
self.subwidget_list['pane'] = _dummyPanedWindow(self, 'pane',
destroy_physically=0)
self.subwidget_list['hlist'] = _dummyHList(self, 'hlist')
self.subwidget_list['shlist'] = _dummyScrolledHList(self, 'shlist')
def add(self, name, cnf={}, **kw):
self.tk.call(self._w, 'add', name, *self._options(cnf, kw))
self.subwidget_list[name] = TixSubWidget(self, name)
return self.subwidget_list[name]
def page(self, name):
return self.subwidget(name)
def pages(self):
# Can't call subwidgets_all directly because we don't want .nbframe
names = self.tk.split(self.tk.call(self._w, 'pages'))
ret = []
for x in names:
ret.append(self.subwidget(x))
return ret
def raise_page(self, name): # raise is a python keyword
self.tk.call(self._w, 'raise', name)
class Meter(TixWidget):
"""The Meter widget can be used to show the progress of a background
job which may take a long time to execute.
"""
def __init__(self, master=None, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixMeter',
['options'], cnf, kw)
class NoteBook(TixWidget):
"""NoteBook - Multi-page container widget (tabbed notebook metaphor).
Subwidgets Class
---------- -----
nbframe NoteBookFrame
<pages> page widgets added dynamically with the add method"""
def __init__ (self,master=None,cnf={}, **kw):
TixWidget.__init__(self,master,'tixNoteBook', ['options'], cnf, kw)
self.subwidget_list['nbframe'] = TixSubWidget(self, 'nbframe',
destroy_physically=0)
def add(self, name, cnf={}, **kw):
self.tk.call(self._w, 'add', name, *self._options(cnf, kw))
self.subwidget_list[name] = TixSubWidget(self, name)
return self.subwidget_list[name]
def delete(self, name):
self.tk.call(self._w, 'delete', name)
self.subwidget_list[name].destroy()
del self.subwidget_list[name]
def page(self, name):
return self.subwidget(name)
def pages(self):
# Can't call subwidgets_all directly because we don't want .nbframe
names = self.tk.split(self.tk.call(self._w, 'pages'))
ret = []
for x in names:
ret.append(self.subwidget(x))
return ret
def raise_page(self, name): # raise is a python keyword
self.tk.call(self._w, 'raise', name)
def raised(self):
return self.tk.call(self._w, 'raised')
class NoteBookFrame(TixWidget):
# FIXME: This is dangerous to expose to be called on its own.
pass
class OptionMenu(TixWidget):
"""OptionMenu - creates a menu button of options.
Subwidget Class
--------- -----
menubutton Menubutton
menu Menu"""
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixOptionMenu', ['options'], cnf, kw)
self.subwidget_list['menubutton'] = _dummyMenubutton(self, 'menubutton')
self.subwidget_list['menu'] = _dummyMenu(self, 'menu')
def add_command(self, name, cnf={}, **kw):
self.tk.call(self._w, 'add', 'command', name, *self._options(cnf, kw))
def add_separator(self, name, cnf={}, **kw):
self.tk.call(self._w, 'add', 'separator', name, *self._options(cnf, kw))
def delete(self, name):
self.tk.call(self._w, 'delete', name)
def disable(self, name):
self.tk.call(self._w, 'disable', name)
def enable(self, name):
self.tk.call(self._w, 'enable', name)
class PanedWindow(TixWidget):
"""PanedWindow - Multi-pane container widget
allows the user to interactively manipulate the sizes of several
panes. The panes can be arranged either vertically or horizontally.The
user changes the sizes of the panes by dragging the resize handle
between two panes.
Subwidgets Class
---------- -----
<panes> g/p widgets added dynamically with the add method."""
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixPanedWindow', ['orientation', 'options'], cnf, kw)
# add delete forget panecget paneconfigure panes setsize
def add(self, name, cnf={}, **kw):
self.tk.call(self._w, 'add', name, *self._options(cnf, kw))
self.subwidget_list[name] = TixSubWidget(self, name,
check_intermediate=0)
return self.subwidget_list[name]
def delete(self, name):
self.tk.call(self._w, 'delete', name)
self.subwidget_list[name].destroy()
del self.subwidget_list[name]
def forget(self, name):
self.tk.call(self._w, 'forget', name)
def panecget(self, entry, opt):
return self.tk.call(self._w, 'panecget', entry, opt)
def paneconfigure(self, entry, cnf={}, **kw):
if cnf is None:
return _lst2dict(
self.tk.split(
self.tk.call(self._w, 'paneconfigure', entry)))
self.tk.call(self._w, 'paneconfigure', entry, *self._options(cnf, kw))
def panes(self):
names = self.tk.call(self._w, 'panes')
ret = []
for x in names:
ret.append(self.subwidget(x))
return ret
class PopupMenu(TixWidget):
"""PopupMenu widget can be used as a replacement of the tk_popup command.
The advantage of the Tix PopupMenu widget is it requires less application
code to manipulate.
Subwidgets Class
---------- -----
menubutton Menubutton
menu Menu"""
# FIXME: It should inherit -superclass tixShell
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixPopupMenu', ['options'], cnf, kw)
self.subwidget_list['menubutton'] = _dummyMenubutton(self, 'menubutton')
self.subwidget_list['menu'] = _dummyMenu(self, 'menu')
def bind_widget(self, widget):
self.tk.call(self._w, 'bind', widget._w)
def unbind_widget(self, widget):
self.tk.call(self._w, 'unbind', widget._w)
def post_widget(self, widget, x, y):
self.tk.call(self._w, 'post', widget._w, x, y)
class ResizeHandle(TixWidget):
"""Internal widget to draw resize handles on Scrolled widgets."""
def __init__(self, master, cnf={}, **kw):
# There seems to be a Tix bug rejecting the configure method
# Let's try making the flags -static
flags = ['options', 'command', 'cursorfg', 'cursorbg',
'handlesize', 'hintcolor', 'hintwidth',
'x', 'y']
# In fact, x y height width are configurable
TixWidget.__init__(self, master, 'tixResizeHandle',
flags, cnf, kw)
def attach_widget(self, widget):
self.tk.call(self._w, 'attachwidget', widget._w)
def detach_widget(self, widget):
self.tk.call(self._w, 'detachwidget', widget._w)
def hide(self, widget):
self.tk.call(self._w, 'hide', widget._w)
def show(self, widget):
self.tk.call(self._w, 'show', widget._w)
class ScrolledHList(TixWidget):
"""ScrolledHList - HList with automatic scrollbars."""
# FIXME: It should inherit -superclass tixScrolledWidget
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixScrolledHList', ['options'],
cnf, kw)
self.subwidget_list['hlist'] = _dummyHList(self, 'hlist')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
class ScrolledListBox(TixWidget):
"""ScrolledListBox - Listbox with automatic scrollbars."""
# FIXME: It should inherit -superclass tixScrolledWidget
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixScrolledListBox', ['options'], cnf, kw)
self.subwidget_list['listbox'] = _dummyListbox(self, 'listbox')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
class ScrolledText(TixWidget):
"""ScrolledText - Text with automatic scrollbars."""
# FIXME: It should inherit -superclass tixScrolledWidget
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixScrolledText', ['options'], cnf, kw)
self.subwidget_list['text'] = _dummyText(self, 'text')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
class ScrolledTList(TixWidget):
"""ScrolledTList - TList with automatic scrollbars."""
# FIXME: It should inherit -superclass tixScrolledWidget
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixScrolledTList', ['options'],
cnf, kw)
self.subwidget_list['tlist'] = _dummyTList(self, 'tlist')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
class ScrolledWindow(TixWidget):
"""ScrolledWindow - Window with automatic scrollbars."""
# FIXME: It should inherit -superclass tixScrolledWidget
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixScrolledWindow', ['options'], cnf, kw)
self.subwidget_list['window'] = _dummyFrame(self, 'window')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
class Select(TixWidget):
"""Select - Container of button subwidgets. It can be used to provide
radio-box or check-box style of selection options for the user.
Subwidgets are buttons added dynamically using the add method."""
# FIXME: It should inherit -superclass tixLabelWidget
def __init__(self, master, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixSelect',
['allowzero', 'radio', 'orientation', 'labelside',
'options'],
cnf, kw)
self.subwidget_list['label'] = _dummyLabel(self, 'label')
def add(self, name, cnf={}, **kw):
self.tk.call(self._w, 'add', name, *self._options(cnf, kw))
self.subwidget_list[name] = _dummyButton(self, name)
return self.subwidget_list[name]
def invoke(self, name):
self.tk.call(self._w, 'invoke', name)
class Shell(TixWidget):
"""Toplevel window.
Subwidgets - None"""
def __init__ (self,master=None,cnf={}, **kw):
TixWidget.__init__(self, master, 'tixShell', ['options', 'title'], cnf, kw)
class DialogShell(TixWidget):
"""Toplevel window, with popup popdown and center methods.
It tells the window manager that it is a dialog window and should be
treated specially. The exact treatment depends on the treatment of
the window manager.
Subwidgets - None"""
# FIXME: It should inherit from Shell
def __init__ (self,master=None,cnf={}, **kw):
TixWidget.__init__(self, master,
'tixDialogShell',
['options', 'title', 'mapped',
'minheight', 'minwidth',
'parent', 'transient'], cnf, kw)
def popdown(self):
self.tk.call(self._w, 'popdown')
def popup(self):
self.tk.call(self._w, 'popup')
def center(self):
self.tk.call(self._w, 'center')
class StdButtonBox(TixWidget):
"""StdButtonBox - Standard Button Box (OK, Apply, Cancel and Help) """
def __init__(self, master=None, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixStdButtonBox',
['orientation', 'options'], cnf, kw)
self.subwidget_list['ok'] = _dummyButton(self, 'ok')
self.subwidget_list['apply'] = _dummyButton(self, 'apply')
self.subwidget_list['cancel'] = _dummyButton(self, 'cancel')
self.subwidget_list['help'] = _dummyButton(self, 'help')
def invoke(self, name):
if self.subwidget_list.has_key(name):
self.tk.call(self._w, 'invoke', name)
class TList(TixWidget):
"""TList - Hierarchy display widget which can be
used to display data in a tabular format. The list entries of a TList
widget are similar to the entries in the Tk listbox widget. The main
differences are (1) the TList widget can display the list entries in a
two dimensional format and (2) you can use graphical images as well as
multiple colors and fonts for the list entries.
Subwidgets - None"""
def __init__ (self,master=None,cnf={}, **kw):
TixWidget.__init__(self, master, 'tixTList', ['options'], cnf, kw)
def active_set(self, index):
self.tk.call(self._w, 'active', 'set', index)
def active_clear(self):
self.tk.call(self._w, 'active', 'clear')
def anchor_set(self, index):
self.tk.call(self._w, 'anchor', 'set', index)
def anchor_clear(self):
self.tk.call(self._w, 'anchor', 'clear')
def delete(self, from_, to=None):
self.tk.call(self._w, 'delete', from_, to)
def dragsite_set(self, index):
self.tk.call(self._w, 'dragsite', 'set', index)
def dragsite_clear(self):
self.tk.call(self._w, 'dragsite', 'clear')
def dropsite_set(self, index):
self.tk.call(self._w, 'dropsite', 'set', index)
def dropsite_clear(self):
self.tk.call(self._w, 'dropsite', 'clear')
def insert(self, index, cnf={}, **kw):
self.tk.call(self._w, 'insert', index, *self._options(cnf, kw))
def info_active(self):
return self.tk.call(self._w, 'info', 'active')
def info_anchor(self):
return self.tk.call(self._w, 'info', 'anchor')
def info_down(self, index):
return self.tk.call(self._w, 'info', 'down', index)
def info_left(self, index):
return self.tk.call(self._w, 'info', 'left', index)
def info_right(self, index):
return self.tk.call(self._w, 'info', 'right', index)
def info_selection(self):
c = self.tk.call(self._w, 'info', 'selection')
return self.tk.splitlist(c)
def info_size(self):
return self.tk.call(self._w, 'info', 'size')
def info_up(self, index):
return self.tk.call(self._w, 'info', 'up', index)
def nearest(self, x, y):
return self.tk.call(self._w, 'nearest', x, y)
def see(self, index):
self.tk.call(self._w, 'see', index)
def selection_clear(self, cnf={}, **kw):
self.tk.call(self._w, 'selection', 'clear', *self._options(cnf, kw))
def selection_includes(self, index):
return self.tk.call(self._w, 'selection', 'includes', index)
def selection_set(self, first, last=None):
self.tk.call(self._w, 'selection', 'set', first, last)
def xview(self, *args):
self.tk.call(self._w, 'xview', *args)
def yview(self, *args):
self.tk.call(self._w, 'yview', *args)
class Tree(TixWidget):
"""Tree - The tixTree widget can be used to display hierachical
data in a tree form. The user can adjust
the view of the tree by opening or closing parts of the tree."""
# FIXME: It should inherit -superclass tixScrolledWidget
def __init__(self, master=None, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixTree',
['options'], cnf, kw)
self.subwidget_list['hlist'] = _dummyHList(self, 'hlist')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
def autosetmode(self):
'''This command calls the setmode method for all the entries in this
Tree widget: if an entry has no child entries, its mode is set to
none. Otherwise, if the entry has any hidden child entries, its mode is
set to open; otherwise its mode is set to close.'''
self.tk.call(self._w, 'autosetmode')
def close(self, entrypath):
'''Close the entry given by entryPath if its mode is close.'''
self.tk.call(self._w, 'close', entrypath)
def getmode(self, entrypath):
'''Returns the current mode of the entry given by entryPath.'''
return self.tk.call(self._w, 'getmode', entrypath)
def open(self, entrypath):
'''Open the entry given by entryPath if its mode is open.'''
self.tk.call(self._w, 'open', entrypath)
def setmode(self, entrypath, mode='none'):
'''This command is used to indicate whether the entry given by
entryPath has children entries and whether the children are visible. mode
must be one of open, close or none. If mode is set to open, a (+)
indicator is drawn next the the entry. If mode is set to close, a (-)
indicator is drawn next the the entry. If mode is set to none, no
indicators will be drawn for this entry. The default mode is none. The
open mode indicates the entry has hidden children and this entry can be
opened by the user. The close mode indicates that all the children of the
entry are now visible and the entry can be closed by the user.'''
self.tk.call(self._w, 'setmode', entrypath, mode)
# Could try subclassing Tree for CheckList - would need another arg to init
class CheckList(TixWidget):
"""The CheckList widget
displays a list of items to be selected by the user. CheckList acts
similarly to the Tk checkbutton or radiobutton widgets, except it is
capable of handling many more items than checkbuttons or radiobuttons.
"""
# FIXME: It should inherit -superclass tixTree
def __init__(self, master=None, cnf={}, **kw):
TixWidget.__init__(self, master, 'tixCheckList',
['options'], cnf, kw)
self.subwidget_list['hlist'] = _dummyHList(self, 'hlist')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
def autosetmode(self):
'''This command calls the setmode method for all the entries in this
Tree widget: if an entry has no child entries, its mode is set to
none. Otherwise, if the entry has any hidden child entries, its mode is
set to open; otherwise its mode is set to close.'''
self.tk.call(self._w, 'autosetmode')
def close(self, entrypath):
'''Close the entry given by entryPath if its mode is close.'''
self.tk.call(self._w, 'close', entrypath)
def getmode(self, entrypath):
'''Returns the current mode of the entry given by entryPath.'''
return self.tk.call(self._w, 'getmode', entrypath)
def open(self, entrypath):
'''Open the entry given by entryPath if its mode is open.'''
self.tk.call(self._w, 'open', entrypath)
def getselection(self, mode='on'):
'''Returns a list of items whose status matches status. If status is
not specified, the list of items in the "on" status will be returned.
Mode can be on, off, default'''
c = self.tk.split(self.tk.call(self._w, 'getselection', mode))
return self.tk.splitlist(c)
def getstatus(self, entrypath):
'''Returns the current status of entryPath.'''
return self.tk.call(self._w, 'getstatus', entrypath)
def setstatus(self, entrypath, mode='on'):
'''Sets the status of entryPath to be status. A bitmap will be
displayed next to the entry its status is on, off or default.'''
self.tk.call(self._w, 'setstatus', entrypath, mode)
###########################################################################
### The subclassing below is used to instantiate the subwidgets in each ###
### mega widget. This allows us to access their methods directly. ###
###########################################################################
class _dummyButton(Button, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyCheckbutton(Checkbutton, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyEntry(Entry, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyFrame(Frame, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyLabel(Label, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyListbox(Listbox, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyMenu(Menu, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyMenubutton(Menubutton, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyScrollbar(Scrollbar, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyText(Text, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyScrolledListBox(ScrolledListBox, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
self.subwidget_list['listbox'] = _dummyListbox(self, 'listbox')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
class _dummyHList(HList, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyScrolledHList(ScrolledHList, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
self.subwidget_list['hlist'] = _dummyHList(self, 'hlist')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
class _dummyTList(TList, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyComboBox(ComboBox, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, ['fancy',destroy_physically])
self.subwidget_list['label'] = _dummyLabel(self, 'label')
self.subwidget_list['entry'] = _dummyEntry(self, 'entry')
self.subwidget_list['arrow'] = _dummyButton(self, 'arrow')
self.subwidget_list['slistbox'] = _dummyScrolledListBox(self,
'slistbox')
try:
self.subwidget_list['tick'] = _dummyButton(self, 'tick')
#cross Button : present if created with the fancy option
self.subwidget_list['cross'] = _dummyButton(self, 'cross')
except TypeError:
# unavailable when -fancy not specified
pass
class _dummyDirList(DirList, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
self.subwidget_list['hlist'] = _dummyHList(self, 'hlist')
self.subwidget_list['vsb'] = _dummyScrollbar(self, 'vsb')
self.subwidget_list['hsb'] = _dummyScrollbar(self, 'hsb')
class _dummyDirSelectBox(DirSelectBox, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
self.subwidget_list['dirlist'] = _dummyDirList(self, 'dirlist')
self.subwidget_list['dircbx'] = _dummyFileComboBox(self, 'dircbx')
class _dummyExFileSelectBox(ExFileSelectBox, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
self.subwidget_list['cancel'] = _dummyButton(self, 'cancel')
self.subwidget_list['ok'] = _dummyButton(self, 'ok')
self.subwidget_list['hidden'] = _dummyCheckbutton(self, 'hidden')
self.subwidget_list['types'] = _dummyComboBox(self, 'types')
self.subwidget_list['dir'] = _dummyComboBox(self, 'dir')
self.subwidget_list['dirlist'] = _dummyScrolledListBox(self, 'dirlist')
self.subwidget_list['file'] = _dummyComboBox(self, 'file')
self.subwidget_list['filelist'] = _dummyScrolledListBox(self, 'filelist')
class _dummyFileSelectBox(FileSelectBox, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
self.subwidget_list['dirlist'] = _dummyScrolledListBox(self, 'dirlist')
self.subwidget_list['filelist'] = _dummyScrolledListBox(self, 'filelist')
self.subwidget_list['filter'] = _dummyComboBox(self, 'filter')
self.subwidget_list['selection'] = _dummyComboBox(self, 'selection')
class _dummyFileComboBox(ComboBox, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
self.subwidget_list['dircbx'] = _dummyComboBox(self, 'dircbx')
class _dummyStdButtonBox(StdButtonBox, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
self.subwidget_list['ok'] = _dummyButton(self, 'ok')
self.subwidget_list['apply'] = _dummyButton(self, 'apply')
self.subwidget_list['cancel'] = _dummyButton(self, 'cancel')
self.subwidget_list['help'] = _dummyButton(self, 'help')
class _dummyNoteBookFrame(NoteBookFrame, TixSubWidget):
def __init__(self, master, name, destroy_physically=0):
TixSubWidget.__init__(self, master, name, destroy_physically)
class _dummyPanedWindow(PanedWindow, TixSubWidget):
def __init__(self, master, name, destroy_physically=1):
TixSubWidget.__init__(self, master, name, destroy_physically)
########################
### Utility Routines ###
########################
#mike Should tixDestroy be exposed as a wrapper? - but not for widgets.
def OptionName(widget):
'''Returns the qualified path name for the widget. Normally used to set
default options for subwidgets. See tixwidgets.py'''
return widget.tk.call('tixOptionName', widget._w)
# Called with a dictionary argument of the form
# {'*.c':'C source files', '*.txt':'Text Files', '*':'All files'}
# returns a string which can be used to configure the fsbox file types
# in an ExFileSelectBox. i.e.,
# '{{*} {* - All files}} {{*.c} {*.c - C source files}} {{*.txt} {*.txt - Text Files}}'
def FileTypeList(dict):
s = ''
for type in dict.keys():
s = s + '{{' + type + '} {' + type + ' - ' + dict[type] + '}} '
return s
# Still to be done:
# tixIconView
class CObjView(TixWidget):
"""This file implements the Canvas Object View widget. This is a base
class of IconView. It implements automatic placement/adjustment of the
scrollbars according to the canvas objects inside the canvas subwidget.
The scrollbars are adjusted so that the canvas is just large enough
to see all the objects.
"""
# FIXME: It should inherit -superclass tixScrolledWidget
pass
class Grid(TixWidget):
'''The Tix Grid command creates a new window and makes it into a
tixGrid widget. Additional options, may be specified on the command
line or in the option database to configure aspects such as its cursor
and relief.
A Grid widget displays its contents in a two dimensional grid of cells.
Each cell may contain one Tix display item, which may be in text,
graphics or other formats. See the DisplayStyle class for more information
about Tix display items. Individual cells, or groups of cells, can be
formatted with a wide range of attributes, such as its color, relief and
border.
Subwidgets - None'''
# valid specific resources as of Tk 8.4
# editdonecmd, editnotifycmd, floatingcols, floatingrows, formatcmd,
# highlightbackground, highlightcolor, leftmargin, itemtype, selectmode,
# selectunit, topmargin,
def __init__(self, master=None, cnf={}, **kw):
static= []
self.cnf= cnf
TixWidget.__init__(self, master, 'tixGrid', static, cnf, kw)
# valid options as of Tk 8.4
# anchor, bdtype, cget, configure, delete, dragsite, dropsite, entrycget, edit
# entryconfigure, format, geometryinfo, info, index, move, nearest, selection
# set, size, unset, xview, yview
# def anchor option ?args ...?
def anchor_get(self):
"Get the (x,y) coordinate of the current anchor cell"
return self._getints(self.tk.call(self, 'anchor', 'get'))
# def bdtype
# def delete dim from ?to?
def delete_row(self, from_, to=None):
"""Delete rows between from_ and to inclusive.
If to is not provided, delete only row at from_"""
if to is None:
self.tk.call(self, 'delete', 'row', from_)
else:
self.tk.call(self, 'delete', 'row', from_, to)
def delete_column(self, from_, to=None):
"""Delete columns between from_ and to inclusive.
If to is not provided, delete only column at from_"""
if to is None:
self.tk.call(self, 'delete', 'column', from_)
else:
self.tk.call(self, 'delete', 'column', from_, to)
# def edit apply
# def edit set x y
def entrycget(self, x, y, option):
"Get the option value for cell at (x,y)"
return self.tk.call(self, 'entrycget', x, y, option)
def entryconfigure(self, x, y, **kw):
return self.tk.call(self, 'entryconfigure', x, y, *self._options(None, kw))
# def format
# def index
def info_exists(self, x, y):
"Return True if display item exists at (x,y)"
return bool(int(self.tk.call(self, 'info', 'exists', x, y)))
def info_bbox(self, x, y):
# This seems to always return '', at least for 'text' displayitems
return self.tk.call(self, 'info', 'bbox', x, y)
def nearest(self, x, y):
"Return coordinate of cell nearest pixel coordinate (x,y)"
return self._getints(self.tk.call(self, 'nearest', x, y))
# def selection adjust
# def selection clear
# def selection includes
# def selection set
# def selection toggle
# def move dim from to offset
def set(self, x, y, itemtype=None, **kw):
args= self._options(self.cnf, kw)
if itemtype is not None:
args= ('-itemtype', itemtype) + args
self.tk.call(self, 'set', x, y, *args)
# def size dim index ?option value ...?
# def unset x y
def xview(self):
return self._getdoubles(self.tk.call(self, 'xview'))
def xview_moveto(self, fraction):
self.tk.call(self,'xview', 'moveto', fraction)
def xview_scroll(self, count, what="units"):
"Scroll right (count>0) or left <count> of units|pages"
self.tk.call(self, 'xview', 'scroll', count, what)
def yview(self):
return self._getdoubles(self.tk.call(self, 'yview'))
def yview_moveto(self, fraction):
self.tk.call(self,'ysview', 'moveto', fraction)
def yview_scroll(self, count, what="units"):
"Scroll down (count>0) or up <count> of units|pages"
self.tk.call(self, 'yview', 'scroll', count, what)
class ScrolledGrid(Grid):
'''Scrolled Grid widgets'''
# FIXME: It should inherit -superclass tixScrolledWidget
def __init__(self, master=None, cnf={}, **kw):
static= []
self.cnf= cnf
TixWidget.__init__(self, master, 'tixScrolledGrid', static, cnf, kw)
# Symbolic constants for Tk
# Booleans
NO=FALSE=OFF=0
YES=TRUE=ON=1
# -anchor and -sticky
N='n'
S='s'
W='w'
E='e'
NW='nw'
SW='sw'
NE='ne'
SE='se'
NS='ns'
EW='ew'
NSEW='nsew'
CENTER='center'
# -fill
NONE='none'
X='x'
Y='y'
BOTH='both'
# -side
LEFT='left'
TOP='top'
RIGHT='right'
BOTTOM='bottom'
# -relief
RAISED='raised'
SUNKEN='sunken'
FLAT='flat'
RIDGE='ridge'
GROOVE='groove'
SOLID = 'solid'
# -orient
HORIZONTAL='horizontal'
VERTICAL='vertical'
# -tabs
NUMERIC='numeric'
# -wrap
CHAR='char'
WORD='word'
# -align
BASELINE='baseline'
# -bordermode
INSIDE='inside'
OUTSIDE='outside'
# Special tags, marks and insert positions
SEL='sel'
SEL_FIRST='sel.first'
SEL_LAST='sel.last'
END='end'
INSERT='insert'
CURRENT='current'
ANCHOR='anchor'
ALL='all' # e.g. Canvas.delete(ALL)
# Text widget and button states
NORMAL='normal'
DISABLED='disabled'
ACTIVE='active'
# Canvas state
HIDDEN='hidden'
# Menu item types
CASCADE='cascade'
CHECKBUTTON='checkbutton'
COMMAND='command'
RADIOBUTTON='radiobutton'
SEPARATOR='separator'
# Selection modes for list boxes
SINGLE='single'
BROWSE='browse'
MULTIPLE='multiple'
EXTENDED='extended'
# Activestyle for list boxes
# NONE='none' is also valid
DOTBOX='dotbox'
UNDERLINE='underline'
# Various canvas styles
PIESLICE='pieslice'
CHORD='chord'
ARC='arc'
FIRST='first'
LAST='last'
BUTT='butt'
PROJECTING='projecting'
ROUND='round'
BEVEL='bevel'
MITER='miter'
# Arguments to xview/yview
MOVETO='moveto'
SCROLL='scroll'
UNITS='units'
PAGES='pages'
"""Drag-and-drop support for Tkinter.
This is very preliminary. I currently only support dnd *within* one
application, between different windows (or within the same window).
I an trying to make this as generic as possible -- not dependent on
the use of a particular widget or icon type, etc. I also hope that
this will work with Pmw.
To enable an object to be dragged, you must create an event binding
for it that starts the drag-and-drop process. Typically, you should
bind <ButtonPress> to a callback function that you write. The function
should call Tkdnd.dnd_start(source, event), where 'source' is the
object to be dragged, and 'event' is the event that invoked the call
(the argument to your callback function). Even though this is a class
instantiation, the returned instance should not be stored -- it will
be kept alive automatically for the duration of the drag-and-drop.
When a drag-and-drop is already in process for the Tk interpreter, the
call is *ignored*; this normally averts starting multiple simultaneous
dnd processes, e.g. because different button callbacks all
dnd_start().
The object is *not* necessarily a widget -- it can be any
application-specific object that is meaningful to potential
drag-and-drop targets.
Potential drag-and-drop targets are discovered as follows. Whenever
the mouse moves, and at the start and end of a drag-and-drop move, the
Tk widget directly under the mouse is inspected. This is the target
widget (not to be confused with the target object, yet to be
determined). If there is no target widget, there is no dnd target
object. If there is a target widget, and it has an attribute
dnd_accept, this should be a function (or any callable object). The
function is called as dnd_accept(source, event), where 'source' is the
object being dragged (the object passed to dnd_start() above), and
'event' is the most recent event object (generally a <Motion> event;
it can also be <ButtonPress> or <ButtonRelease>). If the dnd_accept()
function returns something other than None, this is the new dnd target
object. If dnd_accept() returns None, or if the target widget has no
dnd_accept attribute, the target widget's parent is considered as the
target widget, and the search for a target object is repeated from
there. If necessary, the search is repeated all the way up to the
root widget. If none of the target widgets can produce a target
object, there is no target object (the target object is None).
The target object thus produced, if any, is called the new target
object. It is compared with the old target object (or None, if there
was no old target widget). There are several cases ('source' is the
source object, and 'event' is the most recent event object):
- Both the old and new target objects are None. Nothing happens.
- The old and new target objects are the same object. Its method
dnd_motion(source, event) is called.
- The old target object was None, and the new target object is not
None. The new target object's method dnd_enter(source, event) is
called.
- The new target object is None, and the old target object is not
None. The old target object's method dnd_leave(source, event) is
called.
- The old and new target objects differ and neither is None. The old
target object's method dnd_leave(source, event), and then the new
target object's method dnd_enter(source, event) is called.
Once this is done, the new target object replaces the old one, and the
Tk mainloop proceeds. The return value of the methods mentioned above
is ignored; if they raise an exception, the normal exception handling
mechanisms take over.
The drag-and-drop processes can end in two ways: a final target object
is selected, or no final target object is selected. When a final
target object is selected, it will always have been notified of the
potential drop by a call to its dnd_enter() method, as described
above, and possibly one or more calls to its dnd_motion() method; its
dnd_leave() method has not been called since the last call to
dnd_enter(). The target is notified of the drop by a call to its
method dnd_commit(source, event).
If no final target object is selected, and there was an old target
object, its dnd_leave(source, event) method is called to complete the
dnd sequence.
Finally, the source object is notified that the drag-and-drop process
is over, by a call to source.dnd_end(target, event), specifying either
the selected target object, or None if no target object was selected.
The source object can use this to implement the commit action; this is
sometimes simpler than to do it in the target's dnd_commit(). The
target's dnd_commit() method could then simply be aliased to
dnd_leave().
At any time during a dnd sequence, the application can cancel the
sequence by calling the cancel() method on the object returned by
dnd_start(). This will call dnd_leave() if a target is currently
active; it will never call dnd_commit().
"""
import tkinter
# The factory function
def dnd_start(source, event):
h = DndHandler(source, event)
if h.root:
return h
else:
return None
# The class that does the work
class DndHandler:
root = None
def __init__(self, source, event):
if event.num > 5:
return
root = event.widget._root()
try:
root.__dnd
return # Don't start recursive dnd
except AttributeError:
root.__dnd = self
self.root = root
self.source = source
self.target = None
self.initial_button = button = event.num
self.initial_widget = widget = event.widget
self.release_pattern = "<B%d-ButtonRelease-%d>" % (button, button)
self.save_cursor = widget['cursor'] or ""
widget.bind(self.release_pattern, self.on_release)
widget.bind("<Motion>", self.on_motion)
widget['cursor'] = "hand2"
def __del__(self):
root = self.root
self.root = None
if root:
try:
del root.__dnd
except AttributeError:
pass
def on_motion(self, event):
x, y = event.x_root, event.y_root
target_widget = self.initial_widget.winfo_containing(x, y)
source = self.source
new_target = None
while target_widget:
try:
attr = target_widget.dnd_accept
except AttributeError:
pass
else:
new_target = attr(source, event)
if new_target:
break
target_widget = target_widget.master
old_target = self.target
if old_target is new_target:
if old_target:
old_target.dnd_motion(source, event)
else:
if old_target:
self.target = None
old_target.dnd_leave(source, event)
if new_target:
new_target.dnd_enter(source, event)
self.target = new_target
def on_release(self, event):
self.finish(event, 1)
def cancel(self, event=None):
self.finish(event, 0)
def finish(self, event, commit=0):
target = self.target
source = self.source
widget = self.initial_widget
root = self.root
try:
del root.__dnd
self.initial_widget.unbind(self.release_pattern)
self.initial_widget.unbind("<Motion>")
widget['cursor'] = self.save_cursor
self.target = self.source = self.initial_widget = self.root = None
if target:
if commit:
target.dnd_commit(source, event)
else:
target.dnd_leave(source, event)
finally:
source.dnd_end(target, event)
# ----------------------------------------------------------------------
# The rest is here for testing and demonstration purposes only!
class Icon:
def __init__(self, name):
self.name = name
self.canvas = self.label = self.id = None
def attach(self, canvas, x=10, y=10):
if canvas is self.canvas:
self.canvas.coords(self.id, x, y)
return
if self.canvas:
self.detach()
if not canvas:
return
label = tkinter.Label(canvas, text=self.name,
borderwidth=2, relief="raised")
id = canvas.create_window(x, y, window=label, anchor="nw")
self.canvas = canvas
self.label = label
self.id = id
label.bind("<ButtonPress>", self.press)
def detach(self):
canvas = self.canvas
if not canvas:
return
id = self.id
label = self.label
self.canvas = self.label = self.id = None
canvas.delete(id)
label.destroy()
def press(self, event):
if dnd_start(self, event):
# where the pointer is relative to the label widget:
self.x_off = event.x
self.y_off = event.y
# where the widget is relative to the canvas:
self.x_orig, self.y_orig = self.canvas.coords(self.id)
def move(self, event):
x, y = self.where(self.canvas, event)
self.canvas.coords(self.id, x, y)
def putback(self):
self.canvas.coords(self.id, self.x_orig, self.y_orig)
def where(self, canvas, event):
# where the corner of the canvas is relative to the screen:
x_org = canvas.winfo_rootx()
y_org = canvas.winfo_rooty()
# where the pointer is relative to the canvas widget:
x = event.x_root - x_org
y = event.y_root - y_org
# compensate for initial pointer offset
return x - self.x_off, y - self.y_off
def dnd_end(self, target, event):
pass
class Tester:
def __init__(self, root):
self.top = tkinter.Toplevel(root)
self.canvas = tkinter.Canvas(self.top, width=100, height=100)
self.canvas.pack(fill="both", expand=1)
self.canvas.dnd_accept = self.dnd_accept
def dnd_accept(self, source, event):
return self
def dnd_enter(self, source, event):
self.canvas.focus_set() # Show highlight border
x, y = source.where(self.canvas, event)
x1, y1, x2, y2 = source.canvas.bbox(source.id)
dx, dy = x2-x1, y2-y1
self.dndid = self.canvas.create_rectangle(x, y, x+dx, y+dy)
self.dnd_motion(source, event)
def dnd_motion(self, source, event):
x, y = source.where(self.canvas, event)
x1, y1, x2, y2 = self.canvas.bbox(self.dndid)
self.canvas.move(self.dndid, x-x1, y-y1)
def dnd_leave(self, source, event):
self.top.focus_set() # Hide highlight border
self.canvas.delete(self.dndid)
self.dndid = None
def dnd_commit(self, source, event):
self.dnd_leave(source, event)
x, y = source.where(self.canvas, event)
source.attach(self.canvas, x, y)
def test():
root = tkinter.Tk()
root.geometry("+1+1")
tkinter.Button(command=root.quit, text="Quit").pack()
t1 = Tester(root)
t1.top.geometry("+1+60")
t2 = Tester(root)
t2.top.geometry("+120+60")
t3 = Tester(root)
t3.top.geometry("+240+60")
i1 = Icon("ICON1")
i2 = Icon("ICON2")
i3 = Icon("ICON3")
i1.attach(t1.canvas)
i2.attach(t2.canvas)
i3.attach(t3.canvas)
root.mainloop()
if __name__ == '__main__':
test()
This source diff could not be displayed because it is too large. You can view the blob instead.
# tk common colour chooser dialogue
#
# this module provides an interface to the native color dialogue
# available in Tk 4.2 and newer.
#
# written by Fredrik Lundh, May 1997
#
# fixed initialcolor handling in August 1998
#
#
# options (all have default values):
#
# - initialcolor: colour to mark as selected when dialog is displayed
# (given as an RGB triplet or a Tk color string)
#
# - parent: which window to place the dialog on top of
#
# - title: dialog title
#
from tkinter.commondialog import Dialog
#
# color chooser class
class Chooser(Dialog):
"Ask for a color"
command = "tk_chooseColor"
def _fixoptions(self):
try:
# make sure initialcolor is a tk color string
color = self.options["initialcolor"]
if type(color) == type(()):
# assume an RGB triplet
self.options["initialcolor"] = "#%02x%02x%02x" % color
except KeyError:
pass
def _fixresult(self, widget, result):
# to simplify application code, the color chooser returns
# an RGB tuple together with the Tk color string
if not result:
return None, None # canceled
r, g, b = widget.winfo_rgb(result)
return (r/256, g/256, b/256), result
#
# convenience stuff
def askcolor(color = None, **options):
"Ask for a color"
if color:
options = options.copy()
options["initialcolor"] = color
return Chooser(**options).show()
# --------------------------------------------------------------------
# test stuff
if __name__ == "__main__":
print "color", askcolor()
# base class for tk common dialogues
#
# this module provides a base class for accessing the common
# dialogues available in Tk 4.2 and newer. use filedialog,
# colorchooser, and messagebox to access the individual
# dialogs.
#
# written by Fredrik Lundh, May 1997
#
from tkinter import *
class Dialog:
command = None
def __init__(self, master=None, **options):
# FIXME: should this be placed on the module level instead?
if TkVersion < 4.2:
raise TclError, "this module requires Tk 4.2 or newer"
self.master = master
self.options = options
if not master and options.get('parent'):
self.master = options['parent']
def _fixoptions(self):
pass # hook
def _fixresult(self, widget, result):
return result # hook
def show(self, **options):
# update instance options
for k, v in options.items():
self.options[k] = v
self._fixoptions()
# we need a dummy widget to properly process the options
# (at least as long as we use Tkinter 1.63)
w = Frame(self.master)
try:
s = w.tk.call(self.command, *w._options(self.options))
s = self._fixresult(w, s)
finally:
try:
# get rid of the widget
w.destroy()
except:
pass
return s
#
# Instant Python
# $Id: tkFileDialog.py 36560 2004-07-18 06:16:08Z tim_one $
#
# tk common file dialogues
#
# this module provides interfaces to the native file dialogues
# available in Tk 4.2 and newer, and the directory dialogue available
# in Tk 8.3 and newer.
#
# written by Fredrik Lundh, May 1997.
#
#
# options (all have default values):
#
# - defaultextension: added to filename if not explicitly given
#
# - filetypes: sequence of (label, pattern) tuples. the same pattern
# may occur with several patterns. use "*" as pattern to indicate
# all files.
#
# - initialdir: initial directory. preserved by dialog instance.
#
# - initialfile: initial file (ignored by the open dialog). preserved
# by dialog instance.
#
# - parent: which window to place the dialog on top of
#
# - title: dialog title
#
# - multiple: if true user may select more than one file
#
# options for the directory chooser:
#
# - initialdir, parent, title: see above
#
# - mustexist: if true, user must pick an existing directory
#
#
from tkCommonDialog import Dialog
class _Dialog(Dialog):
def _fixoptions(self):
try:
# make sure "filetypes" is a tuple
self.options["filetypes"] = tuple(self.options["filetypes"])
except KeyError:
pass
def _fixresult(self, widget, result):
if result:
# keep directory and filename until next time
import os
# convert Tcl path objects to strings
try:
result = result.string
except AttributeError:
# it already is a string
pass
path, file = os.path.split(result)
self.options["initialdir"] = path
self.options["initialfile"] = file
self.filename = result # compatibility
return result
#
# file dialogs
class Open(_Dialog):
"Ask for a filename to open"
command = "tk_getOpenFile"
def _fixresult(self, widget, result):
if isinstance(result, tuple):
# multiple results:
result = tuple([getattr(r, "string", r) for r in result])
if result:
import os
path, file = os.path.split(result[0])
self.options["initialdir"] = path
# don't set initialfile or filename, as we have multiple of these
return result
if not widget.tk.wantobjects() and "multiple" in self.options:
# Need to split result explicitly
return self._fixresult(widget, widget.tk.splitlist(result))
return _Dialog._fixresult(self, widget, result)
class SaveAs(_Dialog):
"Ask for a filename to save as"
command = "tk_getSaveFile"
# the directory dialog has its own _fix routines.
class Directory(Dialog):
"Ask for a directory"
command = "tk_chooseDirectory"
def _fixresult(self, widget, result):
if result:
# convert Tcl path objects to strings
try:
result = result.string
except AttributeError:
# it already is a string
pass
# keep directory until next time
self.options["initialdir"] = result
self.directory = result # compatibility
return result
#
# convenience stuff
def askopenfilename(**options):
"Ask for a filename to open"
return Open(**options).show()
def asksaveasfilename(**options):
"Ask for a filename to save as"
return SaveAs(**options).show()
def askopenfilenames(**options):
"""Ask for multiple filenames to open
Returns a list of filenames or empty list if
cancel button selected
"""
options["multiple"]=1
return Open(**options).show()
# FIXME: are the following perhaps a bit too convenient?
def askopenfile(mode = "r", **options):
"Ask for a filename to open, and returned the opened file"
filename = Open(**options).show()
if filename:
return open(filename, mode)
return None
def askopenfiles(mode = "r", **options):
"""Ask for multiple filenames and return the open file
objects
returns a list of open file objects or an empty list if
cancel selected
"""
files = askopenfilenames(**options)
if files:
ofiles=[]
for filename in files:
ofiles.append(open(filename, mode))
files=ofiles
return files
def asksaveasfile(mode = "w", **options):
"Ask for a filename to save as, and returned the opened file"
filename = SaveAs(**options).show()
if filename:
return open(filename, mode)
return None
def askdirectory (**options):
"Ask for a directory, and return the file name"
return Directory(**options).show()
# --------------------------------------------------------------------
# test stuff
if __name__ == "__main__":
# Since the file name may contain non-ASCII characters, we need
# to find an encoding that likely supports the file name, and
# displays correctly on the terminal.
# Start off with UTF-8
enc = "utf-8"
import sys
# See whether CODESET is defined
try:
import locale
locale.setlocale(locale.LC_ALL,'')
enc = locale.nl_langinfo(locale.CODESET)
except (ImportError, AttributeError):
pass
# dialog for openening files
openfilename=askopenfilename(filetypes=[("all files", "*")])
try:
fp=open(openfilename,"r")
fp.close()
except:
print "Could not open File: "
print sys.exc_info()[1]
print "open", openfilename.encode(enc)
# dialog for saving files
saveasfilename=asksaveasfilename()
print "saveas", saveasfilename.encode(enc)
# Tkinter font wrapper
#
# written by Fredrik Lundh, February 1998
#
# FIXME: should add 'displayof' option where relevant (actual, families,
# measure, and metrics)
#
__version__ = "0.9"
import tkinter
# weight/slant
NORMAL = "normal"
ROMAN = "roman"
BOLD = "bold"
ITALIC = "italic"
def nametofont(name):
"""Given the name of a tk named font, returns a Font representation.
"""
return Font(name=name, exists=True)
class Font:
"""Represents a named font.
Constructor options are:
font -- font specifier (name, system font, or (family, size, style)-tuple)
name -- name to use for this font configuration (defaults to a unique name)
exists -- does a named font by this name already exist?
Creates a new named font if False, points to the existing font if True.
Raises _tkinter.TclError if the assertion is false.
the following are ignored if font is specified:
family -- font 'family', e.g. Courier, Times, Helvetica
size -- font size in points
weight -- font thickness: NORMAL, BOLD
slant -- font slant: ROMAN, ITALIC
underline -- font underlining: false (0), true (1)
overstrike -- font strikeout: false (0), true (1)
"""
def _set(self, kw):
options = []
for k, v in kw.items():
options.append("-"+k)
options.append(str(v))
return tuple(options)
def _get(self, args):
options = []
for k in args:
options.append("-"+k)
return tuple(options)
def _mkdict(self, args):
options = {}
for i in range(0, len(args), 2):
options[args[i][1:]] = args[i+1]
return options
def __init__(self, root=None, font=None, name=None, exists=False, **options):
if not root:
root = tkinter._default_root
if font:
# get actual settings corresponding to the given font
font = root.tk.splitlist(root.tk.call("font", "actual", font))
else:
font = self._set(options)
if not name:
name = "font" + str(id(self))
self.name = name
if exists:
self.delete_font = False
# confirm font exists
if self.name not in root.tk.call("font", "names"):
raise tkinter._tkinter.TclError, "named font %s does not already exist" % (self.name,)
# if font config info supplied, apply it
if font:
root.tk.call("font", "configure", self.name, *font)
else:
# create new font (raises TclError if the font exists)
root.tk.call("font", "create", self.name, *font)
self.delete_font = True
# backlinks!
self._root = root
self._split = root.tk.splitlist
self._call = root.tk.call
def __str__(self):
return self.name
def __eq__(self, other):
return self.name == other.name and isinstance(other, Font)
def __getitem__(self, key):
return self.cget(key)
def __setitem__(self, key, value):
self.configure(**{key: value})
def __del__(self):
try:
if self.delete_font:
self._call("font", "delete", self.name)
except (KeyboardInterrupt, SystemExit):
raise
except Exception:
pass
def copy(self):
"Return a distinct copy of the current font"
return Font(self._root, **self.actual())
def actual(self, option=None):
"Return actual font attributes"
if option:
return self._call("font", "actual", self.name, "-"+option)
else:
return self._mkdict(
self._split(self._call("font", "actual", self.name))
)
def cget(self, option):
"Get font attribute"
return self._call("font", "config", self.name, "-"+option)
def config(self, **options):
"Modify font attributes"
if options:
self._call("font", "config", self.name,
*self._set(options))
else:
return self._mkdict(
self._split(self._call("font", "config", self.name))
)
configure = config
def measure(self, text):
"Return text width"
return int(self._call("font", "measure", self.name, text))
def metrics(self, *options):
"""Return font metrics.
For best performance, create a dummy widget
using this font before calling this method."""
if options:
return int(
self._call("font", "metrics", self.name, self._get(options))
)
else:
res = self._split(self._call("font", "metrics", self.name))
options = {}
for i in range(0, len(res), 2):
options[res[i][1:]] = int(res[i+1])
return options
def families(root=None):
"Get font families (as a tuple)"
if not root:
root = tkinter._default_root
return root.tk.splitlist(root.tk.call("font", "families"))
def names(root=None):
"Get names of defined fonts (as a tuple)"
if not root:
root = tkinter._default_root
return root.tk.splitlist(root.tk.call("font", "names"))
# --------------------------------------------------------------------
# test stuff
if __name__ == "__main__":
root = tkinter.Tk()
# create a font
f = Font(family="times", size=30, weight=NORMAL)
print f.actual()
print f.actual("family")
print f.actual("weight")
print f.config()
print f.cget("family")
print f.cget("weight")
print names()
print f.measure("hello"), f.metrics("linespace")
print f.metrics()
f = Font(font=("Courier", 20, "bold"))
print f.measure("hello"), f.metrics("linespace")
w = tkinter.Label(root, text="Hello, world", font=f)
w.pack()
w = tkinter.Button(root, text="Quit!", command=root.destroy)
w.pack()
fb = Font(font=w["font"]).copy()
fb.config(weight=BOLD)
w.config(font=fb)
tkinter.mainloop()
# tk common message boxes
#
# this module provides an interface to the native message boxes
# available in Tk 4.2 and newer.
#
# written by Fredrik Lundh, May 1997
#
#
# options (all have default values):
#
# - default: which button to make default (one of the reply codes)
#
# - icon: which icon to display (see below)
#
# - message: the message to display
#
# - parent: which window to place the dialog on top of
#
# - title: dialog title
#
# - type: dialog type; that is, which buttons to display (see below)
#
from tkinter.commondialog import Dialog
#
# constants
# icons
ERROR = "error"
INFO = "info"
QUESTION = "question"
WARNING = "warning"
# types
ABORTRETRYIGNORE = "abortretryignore"
OK = "ok"
OKCANCEL = "okcancel"
RETRYCANCEL = "retrycancel"
YESNO = "yesno"
YESNOCANCEL = "yesnocancel"
# replies
ABORT = "abort"
RETRY = "retry"
IGNORE = "ignore"
OK = "ok"
CANCEL = "cancel"
YES = "yes"
NO = "no"
#
# message dialog class
class Message(Dialog):
"A message box"
command = "tk_messageBox"
#
# convenience stuff
# Rename _icon and _type options to allow overriding them in options
def _show(title=None, message=None, _icon=None, _type=None, **options):
if _icon and "icon" not in options: options["icon"] = _icon
if _type and "type" not in options: options["type"] = _type
if title: options["title"] = title
if message: options["message"] = message
res = Message(**options).show()
# In some Tcl installations, Tcl converts yes/no into a boolean
if isinstance(res, bool):
if res: return YES
return NO
return res
def showinfo(title=None, message=None, **options):
"Show an info message"
return _show(title, message, INFO, OK, **options)
def showwarning(title=None, message=None, **options):
"Show a warning message"
return _show(title, message, WARNING, OK, **options)
def showerror(title=None, message=None, **options):
"Show an error message"
return _show(title, message, ERROR, OK, **options)
def askquestion(title=None, message=None, **options):
"Ask a question"
return _show(title, message, QUESTION, YESNO, **options)
def askokcancel(title=None, message=None, **options):
"Ask if operation should proceed; return true if the answer is ok"
s = _show(title, message, QUESTION, OKCANCEL, **options)
return s == OK
def askyesno(title=None, message=None, **options):
"Ask a question; return true if the answer is yes"
s = _show(title, message, QUESTION, YESNO, **options)
return s == YES
def askyesnocancel(title=None, message=None, **options):
"Ask a question; return true if the answer is yes, None if cancelled."
s = _show(title, message, QUESTION, YESNOCANCEL, **options)
# s might be a Tcl index object, so convert it to a string
s = str(s)
if s == CANCEL:
return None
return s == YES
def askretrycancel(title=None, message=None, **options):
"Ask if operation should be retried; return true if the answer is yes"
s = _show(title, message, WARNING, RETRYCANCEL, **options)
return s == RETRY
# --------------------------------------------------------------------
# test stuff
if __name__ == "__main__":
print "info", showinfo("Spam", "Egg Information")
print "warning", showwarning("Spam", "Egg Warning")
print "error", showerror("Spam", "Egg Alert")
print "question", askquestion("Spam", "Question?")
print "proceed", askokcancel("Spam", "Proceed?")
print "yes/no", askyesno("Spam", "Got it?")
print "yes/no/cancel", askyesnocancel("Spam", "Want it?")
print "try again", askretrycancel("Spam", "Try again?")
#
# An Introduction to Tkinter
# tkSimpleDialog.py
#
# Copyright (c) 1997 by Fredrik Lundh
#
# fredrik@pythonware.com
# http://www.pythonware.com
#
# --------------------------------------------------------------------
# dialog base class
'''Dialog boxes
This module handles dialog boxes. It contains the following
public symbols:
Dialog -- a base class for dialogs
askinteger -- get an integer from the user
askfloat -- get a float from the user
askstring -- get a string from the user
'''
from Tkinter import *
class Dialog(Toplevel):
'''Class to open dialogs.
This class is intended as a base class for custom dialogs
'''
def __init__(self, parent, title = None):
'''Initialize a dialog.
Arguments:
parent -- a parent window (the application window)
title -- the dialog title
'''
Toplevel.__init__(self, parent)
# If the master is not viewable, don't
# make the child transient, or else it
# would be opened withdrawn
if parent.winfo_viewable():
self.transient(parent)
if title:
self.title(title)
self.parent = parent
self.result = None
body = Frame(self)
self.initial_focus = self.body(body)
body.pack(padx=5, pady=5)
self.buttonbox()
self.wait_visibility() # window needs to be visible for the grab
self.grab_set()
if not self.initial_focus:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
if self.parent is not None:
self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
parent.winfo_rooty()+50))
self.initial_focus.focus_set()
self.wait_window(self)
def destroy(self):
'''Destroy the window'''
self.initial_focus = None
Toplevel.destroy(self)
#
# construction hooks
def body(self, master):
'''create dialog body.
return widget that should have initial focus.
This method should be overridden, and is called
by the __init__ method.
'''
pass
def buttonbox(self):
'''add standard button box.
override if you do not want the standard buttons
'''
box = Frame(self)
w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
w.pack(side=LEFT, padx=5, pady=5)
w = Button(box, text="Cancel", width=10, command=self.cancel)
w.pack(side=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()
try:
self.apply()
finally:
self.cancel()
def cancel(self, event=None):
# put focus back to the parent window
if self.parent is not None:
self.parent.focus_set()
self.destroy()
#
# command hooks
def validate(self):
'''validate the data
This method is called automatically to validate the data before the
dialog is destroyed. By default, it always validates OK.
'''
return 1 # override
def apply(self):
'''process the data
This method is called automatically to process the data, *after*
the dialog is destroyed. By default, it does nothing.
'''
pass # override
# --------------------------------------------------------------------
# convenience dialogues
class _QueryDialog(Dialog):
def __init__(self, title, prompt,
initialvalue=None,
minvalue = None, maxvalue = None,
parent = None):
if not parent:
import Tkinter
parent = Tkinter._default_root
self.prompt = prompt
self.minvalue = minvalue
self.maxvalue = maxvalue
self.initialvalue = initialvalue
Dialog.__init__(self, parent, title)
def destroy(self):
self.entry = None
Dialog.destroy(self)
def body(self, master):
w = Label(master, text=self.prompt, justify=LEFT)
w.grid(row=0, padx=5, sticky=W)
self.entry = Entry(master, name="entry")
self.entry.grid(row=1, padx=5, sticky=W+E)
if self.initialvalue:
self.entry.insert(0, self.initialvalue)
self.entry.select_range(0, END)
return self.entry
def validate(self):
import tkMessageBox
try:
result = self.getresult()
except ValueError:
tkMessageBox.showwarning(
"Illegal value",
self.errormessage + "\nPlease try again",
parent = self
)
return 0
if self.minvalue is not None and result < self.minvalue:
tkMessageBox.showwarning(
"Too small",
"The allowed minimum value is %s. "
"Please try again." % self.minvalue,
parent = self
)
return 0
if self.maxvalue is not None and result > self.maxvalue:
tkMessageBox.showwarning(
"Too large",
"The allowed maximum value is %s. "
"Please try again." % self.maxvalue,
parent = self
)
return 0
self.result = result
return 1
class _QueryInteger(_QueryDialog):
errormessage = "Not an integer."
def getresult(self):
return int(self.entry.get())
def askinteger(title, prompt, **kw):
'''get an integer from the user
Arguments:
title -- the dialog title
prompt -- the label text
**kw -- see SimpleDialog class
Return value is an integer
'''
d = _QueryInteger(title, prompt, **kw)
return d.result
class _QueryFloat(_QueryDialog):
errormessage = "Not a floating point value."
def getresult(self):
return float(self.entry.get())
def askfloat(title, prompt, **kw):
'''get a float from the user
Arguments:
title -- the dialog title
prompt -- the label text
**kw -- see SimpleDialog class
Return value is a float
'''
d = _QueryFloat(title, prompt, **kw)
return d.result
class _QueryString(_QueryDialog):
def __init__(self, *args, **kw):
if kw.has_key("show"):
self.__show = kw["show"]
del kw["show"]
else:
self.__show = None
_QueryDialog.__init__(self, *args, **kw)
def body(self, master):
entry = _QueryDialog.body(self, master)
if self.__show is not None:
entry.configure(show=self.__show)
return entry
def getresult(self):
return self.entry.get()
def askstring(title, prompt, **kw):
'''get a string from the user
Arguments:
title -- the dialog title
prompt -- the label text
**kw -- see SimpleDialog class
Return value is a string
'''
d = _QueryString(title, prompt, **kw)
return d.result
if __name__ == "__main__":
root = Tk()
root.update()
print askinteger("Spam", "Egg count", initialvalue=12*12)
print askfloat("Spam", "Egg weight\n(in tons)", minvalue=1, maxvalue=100)
print askstring("Spam", "Egg label")
# LogoMation-like turtle graphics
"""
Turtle graphics is a popular way for introducing programming to
kids. It was part of the original Logo programming language developed
by Wally Feurzeig and Seymour Papert in 1966.
Imagine a robotic turtle starting at (0, 0) in the x-y plane. Give it
the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
the direction it is facing, drawing a line as it moves. Give it the
command turtle.left(25), and it rotates in-place 25 degrees clockwise.
By combining together these and similar commands, intricate shapes and
pictures can easily be drawn.
"""
from math import * # Also for export
from time import sleep
import tkinter
speeds = ['fastest', 'fast', 'normal', 'slow', 'slowest']
class Error(Exception):
pass
class RawPen:
def __init__(self, canvas):
self._canvas = canvas
self._items = []
self._tracing = 1
self._arrow = 0
self._delay = 10 # default delay for drawing
self._angle = 0.0
self.degrees()
self.reset()
def degrees(self, fullcircle=360.0):
""" Set angle measurement units to degrees.
Example:
>>> turtle.degrees()
"""
# Don't try to change _angle if it is 0, because
# _fullcircle might not be set, yet
if self._angle:
self._angle = (self._angle / self._fullcircle) * fullcircle
self._fullcircle = fullcircle
self._invradian = pi / (fullcircle * 0.5)
def radians(self):
""" Set the angle measurement units to radians.
Example:
>>> turtle.radians()
"""
self.degrees(2.0*pi)
def reset(self):
""" Clear the screen, re-center the pen, and set variables to
the default values.
Example:
>>> turtle.position()
[0.0, -22.0]
>>> turtle.heading()
100.0
>>> turtle.reset()
>>> turtle.position()
[0.0, 0.0]
>>> turtle.heading()
0.0
"""
canvas = self._canvas
self._canvas.update()
width = canvas.winfo_width()
height = canvas.winfo_height()
if width <= 1:
width = canvas['width']
if height <= 1:
height = canvas['height']
self._origin = float(width)/2.0, float(height)/2.0
self._position = self._origin
self._angle = 0.0
self._drawing = 1
self._width = 1
self._color = "black"
self._filling = 0
self._path = []
self.clear()
canvas._root().tkraise()
def clear(self):
""" Clear the screen. The turtle does not move.
Example:
>>> turtle.clear()
"""
self.fill(0)
canvas = self._canvas
items = self._items
self._items = []
for item in items:
canvas.delete(item)
self._delete_turtle()
self._draw_turtle()
def tracer(self, flag):
""" Set tracing on if flag is True, and off if it is False.
Tracing means line are drawn more slowly, with an
animation of an arrow along the line.
Example:
>>> turtle.tracer(False) # turns off Tracer
"""
self._tracing = flag
if not self._tracing:
self._delete_turtle()
self._draw_turtle()
def forward(self, distance):
""" Go forward distance steps.
Example:
>>> turtle.position()
[0.0, 0.0]
>>> turtle.forward(25)
>>> turtle.position()
[25.0, 0.0]
>>> turtle.forward(-75)
>>> turtle.position()
[-50.0, 0.0]
"""
x0, y0 = start = self._position
x1 = x0 + distance * cos(self._angle*self._invradian)
y1 = y0 - distance * sin(self._angle*self._invradian)
self._goto(x1, y1)
def backward(self, distance):
""" Go backwards distance steps.
The turtle's heading does not change.
Example:
>>> turtle.position()
[0.0, 0.0]
>>> turtle.backward(30)
>>> turtle.position()
[-30.0, 0.0]
"""
self.forward(-distance)
def left(self, angle):
""" Turn left angle units (units are by default degrees,
but can be set via the degrees() and radians() functions.)
When viewed from above, the turning happens in-place around
its front tip.
Example:
>>> turtle.heading()
22
>>> turtle.left(45)
>>> turtle.heading()
67.0
"""
self._angle = (self._angle + angle) % self._fullcircle
self._draw_turtle()
def right(self, angle):
""" Turn right angle units (units are by default degrees,
but can be set via the degrees() and radians() functions.)
When viewed from above, the turning happens in-place around
its front tip.
Example:
>>> turtle.heading()
22
>>> turtle.right(45)
>>> turtle.heading()
337.0
"""
self.left(-angle)
def up(self):
""" Pull the pen up -- no drawing when moving.
Example:
>>> turtle.up()
"""
self._drawing = 0
def down(self):
""" Put the pen down -- draw when moving.
Example:
>>> turtle.down()
"""
self._drawing = 1
def width(self, width):
""" Set the line to thickness to width.
Example:
>>> turtle.width(10)
"""
self._width = float(width)
def color(self, *args):
""" Set the pen color.
Three input formats are allowed:
color(s)
s is a Tk specification string, such as "red" or "yellow"
color((r, g, b))
*a tuple* of r, g, and b, which represent, an RGB color,
and each of r, g, and b are in the range [0..1]
color(r, g, b)
r, g, and b represent an RGB color, and each of r, g, and b
are in the range [0..1]
Example:
>>> turtle.color('brown')
>>> tup = (0.2, 0.8, 0.55)
>>> turtle.color(tup)
>>> turtle.color(0, .5, 0)
"""
if not args:
raise Error, "no color arguments"
if len(args) == 1:
color = args[0]
if type(color) == type(""):
# Test the color first
try:
id = self._canvas.create_line(0, 0, 0, 0, fill=color)
except tkinter.TclError:
raise Error, "bad color string: %r" % (color,)
self._set_color(color)
return
try:
r, g, b = color
except:
raise Error, "bad color sequence: %r" % (color,)
else:
try:
r, g, b = args
except:
raise Error, "bad color arguments: %r" % (args,)
assert 0 <= r <= 1
assert 0 <= g <= 1
assert 0 <= b <= 1
x = 255.0
y = 0.5
self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y)))
def _set_color(self,color):
self._color = color
self._draw_turtle()
def write(self, text, move=False):
""" Write text at the current pen position.
If move is true, the pen is moved to the bottom-right corner
of the text. By default, move is False.
Example:
>>> turtle.write('The race is on!')
>>> turtle.write('Home = (0, 0)', True)
"""
x, y = self._position
x = x-1 # correction -- calibrated for Windows
item = self._canvas.create_text(x, y,
text=str(text), anchor="sw",
fill=self._color)
self._items.append(item)
if move:
x0, y0, x1, y1 = self._canvas.bbox(item)
self._goto(x1, y1)
self._draw_turtle()
def fill(self, flag):
""" Call fill(1) before drawing the shape you
want to fill, and fill(0) when done.
Example:
>>> turtle.fill(1)
>>> turtle.forward(100)
>>> turtle.left(90)
>>> turtle.forward(100)
>>> turtle.left(90)
>>> turtle.forward(100)
>>> turtle.left(90)
>>> turtle.forward(100)
>>> turtle.fill(0)
"""
if self._filling:
path = tuple(self._path)
smooth = self._filling < 0
if len(path) > 2:
item = self._canvas._create('polygon', path,
{'fill': self._color,
'smooth': smooth})
self._items.append(item)
self._path = []
self._filling = flag
if flag:
self._path.append(self._position)
def begin_fill(self):
""" Called just before drawing a shape to be filled.
Must eventually be followed by a corresponding end_fill() call.
Otherwise it will be ignored.
Example:
>>> turtle.begin_fill()
>>> turtle.forward(100)
>>> turtle.left(90)
>>> turtle.forward(100)
>>> turtle.left(90)
>>> turtle.forward(100)
>>> turtle.left(90)
>>> turtle.forward(100)
>>> turtle.end_fill()
"""
self._path = [self._position]
self._filling = 1
def end_fill(self):
""" Called after drawing a shape to be filled.
Example:
>>> turtle.begin_fill()
>>> turtle.forward(100)
>>> turtle.left(90)
>>> turtle.forward(100)
>>> turtle.left(90)
>>> turtle.forward(100)
>>> turtle.left(90)
>>> turtle.forward(100)
>>> turtle.end_fill()
"""
self.fill(0)
def circle(self, radius, extent = None):
""" Draw a circle with given radius.
The center is radius units left of the turtle; extent
determines which part of the circle is drawn. If not given,
the entire circle is drawn.
If extent is not a full circle, one endpoint of the arc is the
current pen position. The arc is drawn in a counter clockwise
direction if radius is positive, otherwise in a clockwise
direction. In the process, the direction of the turtle is
changed by the amount of the extent.
>>> turtle.circle(50)
>>> turtle.circle(120, 180) # half a circle
"""
if extent is None:
extent = self._fullcircle
frac = abs(extent)/self._fullcircle
steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
w = 1.0 * extent / steps
w2 = 0.5 * w
l = 2.0 * radius * sin(w2*self._invradian)
if radius < 0:
l, w, w2 = -l, -w, -w2
self.left(w2)
for i in range(steps):
self.forward(l)
self.left(w)
self.right(w2)
def heading(self):
""" Return the turtle's current heading.
Example:
>>> turtle.heading()
67.0
"""
return self._angle
def setheading(self, angle):
""" Set the turtle facing the given angle.
Here are some common directions in degrees:
0 - east
90 - north
180 - west
270 - south
Example:
>>> turtle.setheading(90)
>>> turtle.heading()
90
>>> turtle.setheading(128)
>>> turtle.heading()
128
"""
self._angle = angle
self._draw_turtle()
def window_width(self):
""" Returns the width of the turtle window.
Example:
>>> turtle.window_width()
640
"""
width = self._canvas.winfo_width()
if width <= 1: # the window isn't managed by a geometry manager
width = self._canvas['width']
return width
def window_height(self):
""" Return the height of the turtle window.
Example:
>>> turtle.window_height()
768
"""
height = self._canvas.winfo_height()
if height <= 1: # the window isn't managed by a geometry manager
height = self._canvas['height']
return height
def position(self):
""" Return the current (x, y) location of the turtle.
Example:
>>> turtle.position()
[0.0, 240.0]
"""
x0, y0 = self._origin
x1, y1 = self._position
return [x1-x0, -y1+y0]
def setx(self, xpos):
""" Set the turtle's x coordinate to be xpos.
Example:
>>> turtle.position()
[10.0, 240.0]
>>> turtle.setx(10)
>>> turtle.position()
[10.0, 240.0]
"""
x0, y0 = self._origin
x1, y1 = self._position
self._goto(x0+xpos, y1)
def sety(self, ypos):
""" Set the turtle's y coordinate to be ypos.
Example:
>>> turtle.position()
[0.0, 0.0]
>>> turtle.sety(-22)
>>> turtle.position()
[0.0, -22.0]
"""
x0, y0 = self._origin
x1, y1 = self._position
self._goto(x1, y0-ypos)
def towards(self, *args):
"""Returs the angle, which corresponds to the line
from turtle-position to point (x,y).
Argument can be two coordinates or one pair of coordinates
or a RawPen/Pen instance.
Example:
>>> turtle.position()
[10.0, 10.0]
>>> turtle.towards(0,0)
225.0
"""
if len(args) == 2:
x, y = args
else:
arg = args[0]
if isinstance(arg, RawPen):
x, y = arg.position()
else:
x, y = arg
x0, y0 = self.position()
dx = x - x0
dy = y - y0
return (atan2(dy,dx) / self._invradian) % self._fullcircle
def goto(self, *args):
""" Go to the given point.
If the pen is down, then a line will be drawn. The turtle's
orientation does not change.
Two input formats are accepted:
goto(x, y)
go to point (x, y)
goto((x, y))
go to point (x, y)
Example:
>>> turtle.position()
[0.0, 0.0]
>>> turtle.goto(50, -45)
>>> turtle.position()
[50.0, -45.0]
"""
if len(args) == 1:
try:
x, y = args[0]
except:
raise Error, "bad point argument: %r" % (args[0],)
else:
try:
x, y = args
except:
raise Error, "bad coordinates: %r" % (args[0],)
x0, y0 = self._origin
self._goto(x0+x, y0-y)
def _goto(self, x1, y1):
x0, y0 = self._position
self._position = map(float, (x1, y1))
if self._filling:
self._path.append(self._position)
if self._drawing:
if self._tracing:
dx = float(x1 - x0)
dy = float(y1 - y0)
distance = hypot(dx, dy)
nhops = int(distance)
item = self._canvas.create_line(x0, y0, x0, y0,
width=self._width,
capstyle="round",
fill=self._color)
try:
for i in range(1, 1+nhops):
x, y = x0 + dx*i/nhops, y0 + dy*i/nhops
self._canvas.coords(item, x0, y0, x, y)
self._draw_turtle((x,y))
self._canvas.update()
self._canvas.after(self._delay)
# in case nhops==0
self._canvas.coords(item, x0, y0, x1, y1)
self._canvas.itemconfigure(item, arrow="none")
except tkinter.TclError:
# Probably the window was closed!
return
else:
item = self._canvas.create_line(x0, y0, x1, y1,
width=self._width,
capstyle="round",
fill=self._color)
self._items.append(item)
self._draw_turtle()
def speed(self, speed):
""" Set the turtle's speed.
speed must one of these five strings:
'fastest' is a 0 ms delay
'fast' is a 5 ms delay
'normal' is a 10 ms delay
'slow' is a 15 ms delay
'slowest' is a 20 ms delay
Example:
>>> turtle.speed('slow')
"""
try:
speed = speed.strip().lower()
self._delay = speeds.index(speed) * 5
except:
raise ValueError("%r is not a valid speed. speed must be "
"one of %s" % (speed, speeds))
def delay(self, delay):
""" Set the drawing delay in milliseconds.
This is intended to allow finer control of the drawing speed
than the speed() method
Example:
>>> turtle.delay(15)
"""
if int(delay) < 0:
raise ValueError("delay must be greater than or equal to 0")
self._delay = int(delay)
def _draw_turtle(self, position=[]):
if not self._tracing:
self._canvas.update()
return
if position == []:
position = self._position
x,y = position
distance = 8
dx = distance * cos(self._angle*self._invradian)
dy = distance * sin(self._angle*self._invradian)
self._delete_turtle()
self._arrow = self._canvas.create_line(x-dx,y+dy,x,y,
width=self._width,
arrow="last",
capstyle="round",
fill=self._color)
self._canvas.update()
def _delete_turtle(self):
if self._arrow != 0:
self._canvas.delete(self._arrow)
self._arrow = 0
_root = None
_canvas = None
_pen = None
_width = 0.50 # 50% of window width
_height = 0.75 # 75% of window height
_startx = None
_starty = None
_title = "Turtle Graphics" # default title
class Pen(RawPen):
def __init__(self):
global _root, _canvas
if _root is None:
_root = tkinter.Tk()
_root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
_root.title(_title)
if _canvas is None:
# XXX Should have scroll bars
_canvas = tkinter.Canvas(_root, background="white")
_canvas.pack(expand=1, fill="both")
setup(width=_width, height= _height, startx=_startx, starty=_starty)
RawPen.__init__(self, _canvas)
def _destroy(self):
global _root, _canvas, _pen
root = self._canvas._root()
if root is _root:
_pen = None
_root = None
_canvas = None
root.destroy()
def _getpen():
global _pen
if not _pen:
_pen = Pen()
return _pen
class Turtle(Pen):
pass
"""For documentation of the following functions see
the RawPen methods with the same names
"""
def degrees(): _getpen().degrees()
def radians(): _getpen().radians()
def reset(): _getpen().reset()
def clear(): _getpen().clear()
def tracer(flag): _getpen().tracer(flag)
def forward(distance): _getpen().forward(distance)
def backward(distance): _getpen().backward(distance)
def left(angle): _getpen().left(angle)
def right(angle): _getpen().right(angle)
def up(): _getpen().up()
def down(): _getpen().down()
def width(width): _getpen().width(width)
def color(*args): _getpen().color(*args)
def write(arg, move=0): _getpen().write(arg, move)
def fill(flag): _getpen().fill(flag)
def begin_fill(): _getpen().begin_fill()
def end_fill(): _getpen().end_fill()
def circle(radius, extent=None): _getpen().circle(radius, extent)
def goto(*args): _getpen().goto(*args)
def heading(): return _getpen().heading()
def setheading(angle): _getpen().setheading(angle)
def position(): return _getpen().position()
def window_width(): return _getpen().window_width()
def window_height(): return _getpen().window_height()
def setx(xpos): _getpen().setx(xpos)
def sety(ypos): _getpen().sety(ypos)
def towards(*args): return _getpen().towards(*args)
def done(): _root.mainloop()
def delay(delay): return _getpen().delay(delay)
def speed(speed): return _getpen().speed(speed)
for methodname in dir(RawPen):
""" copies RawPen docstrings to module functions of same name """
if not methodname.startswith("_"):
eval(methodname).__doc__ = RawPen.__dict__[methodname].__doc__
def setup(**geometry):
""" Sets the size and position of the main window.
Keywords are width, height, startx and starty:
width: either a size in pixels or a fraction of the screen.
Default is 50% of screen.
height: either the height in pixels or a fraction of the screen.
Default is 75% of screen.
Setting either width or height to None before drawing will force
use of default geometry as in older versions of turtle.py
startx: starting position in pixels from the left edge of the screen.
Default is to center window. Setting startx to None is the default
and centers window horizontally on screen.
starty: starting position in pixels from the top edge of the screen.
Default is to center window. Setting starty to None is the default
and centers window vertically on screen.
Examples:
>>> setup (width=200, height=200, startx=0, starty=0)
sets window to 200x200 pixels, in upper left of screen
>>> setup(width=.75, height=0.5, startx=None, starty=None)
sets window to 75% of screen by 50% of screen and centers
>>> setup(width=None)
forces use of default geometry as in older versions of turtle.py
"""
global _width, _height, _startx, _starty
width = geometry.get('width',_width)
if width >= 0 or width is None:
_width = width
else:
raise ValueError, "width can not be less than 0"
height = geometry.get('height',_height)
if height >= 0 or height is None:
_height = height
else:
raise ValueError, "height can not be less than 0"
startx = geometry.get('startx', _startx)
if startx >= 0 or startx is None:
_startx = _startx
else:
raise ValueError, "startx can not be less than 0"
starty = geometry.get('starty', _starty)
if starty >= 0 or starty is None:
_starty = starty
else:
raise ValueError, "startx can not be less than 0"
if _root and _width and _height:
if 0 < _width <= 1:
_width = _root.winfo_screenwidth() * +width
if 0 < _height <= 1:
_height = _root.winfo_screenheight() * _height
# center window on screen
if _startx is None:
_startx = (_root.winfo_screenwidth() - _width) / 2
if _starty is None:
_starty = (_root.winfo_screenheight() - _height) / 2
_root.geometry("%dx%d+%d+%d" % (_width, _height, _startx, _starty))
def title(title):
"""Set the window title.
By default this is set to 'Turtle Graphics'
Example:
>>> title("My Window")
"""
global _title
_title = title
def demo():
reset()
tracer(1)
up()
backward(100)
down()
# draw 3 squares; the last filled
width(3)
for i in range(3):
if i == 2:
fill(1)
for j in range(4):
forward(20)
left(90)
if i == 2:
color("maroon")
fill(0)
up()
forward(30)
down()
width(1)
color("black")
# move out of the way
tracer(0)
up()
right(90)
forward(100)
right(90)
forward(100)
right(180)
down()
# some text
write("startstart", 1)
write("start", 1)
color("red")
# staircase
for i in range(5):
forward(20)
left(90)
forward(20)
right(90)
# filled staircase
fill(1)
for i in range(5):
forward(20)
left(90)
forward(20)
right(90)
fill(0)
tracer(1)
# more text
write("end")
def demo2():
# exercises some new and improved features
speed('fast')
width(3)
# draw a segmented half-circle
setheading(towards(0,0))
x,y = position()
r = (x**2+y**2)**.5/2.0
right(90)
pendown = True
for i in range(18):
if pendown:
up()
pendown = False
else:
down()
pendown = True
circle(r,10)
sleep(2)
reset()
left(90)
# draw a series of triangles
l = 10
color("green")
width(3)
left(180)
sp = 5
for i in range(-2,16):
if i > 0:
color(1.0-0.05*i,0,0.05*i)
fill(1)
color("green")
for j in range(3):
forward(l)
left(120)
l += 10
left(15)
if sp > 0:
sp = sp-1
speed(speeds[sp])
color(0.25,0,0.75)
fill(0)
# draw and fill a concave shape
left(120)
up()
forward(70)
right(30)
down()
color("red")
speed("fastest")
fill(1)
for i in range(4):
circle(50,90)
right(90)
forward(30)
right(90)
color("yellow")
fill(0)
left(90)
up()
forward(30)
down();
color("red")
# create a second turtle and make the original pursue and catch it
turtle=Turtle()
turtle.reset()
turtle.left(90)
turtle.speed('normal')
turtle.up()
turtle.goto(280,40)
turtle.left(24)
turtle.down()
turtle.speed('fast')
turtle.color("blue")
turtle.width(2)
speed('fastest')
# turn default turtle towards new turtle object
setheading(towards(turtle))
while ( abs(position()[0]-turtle.position()[0])>4 or
abs(position()[1]-turtle.position()[1])>4):
turtle.forward(3.5)
turtle.left(0.6)
# turn default turtle towards new turtle object
setheading(towards(turtle))
forward(4)
write("CAUGHT! ", move=True)
if __name__ == '__main__':
demo()
sleep(3)
demo2()
done()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment