Import Upstream version 2.7.18
This commit is contained in:
11
Demo/tkinter/README
Normal file
11
Demo/tkinter/README
Normal file
@@ -0,0 +1,11 @@
|
||||
Several collections of example code for Tkinter.
|
||||
|
||||
See the toplevel README for an explanation of the difference between
|
||||
Tkinter and _tkinter, how to enable the Python Tk interface, and where
|
||||
to get Matt Conway's lifesaver document.
|
||||
|
||||
Subdirectories:
|
||||
|
||||
guido my original example set (fairly random collection)
|
||||
matt Matt Conway's examples, to go with his lifesaver document
|
||||
ttk Examples using the ttk module
|
||||
452
Demo/tkinter/guido/AttrDialog.py
Normal file
452
Demo/tkinter/guido/AttrDialog.py
Normal file
@@ -0,0 +1,452 @@
|
||||
|
||||
# The options of a widget are described by the following attributes
|
||||
# of the Pack and Widget dialogs:
|
||||
#
|
||||
# Dialog.current: {name: value}
|
||||
# -- changes during Widget's lifetime
|
||||
#
|
||||
# Dialog.options: {name: (default, klass)}
|
||||
# -- depends on widget class only
|
||||
#
|
||||
# Dialog.classes: {klass: (v0, v1, v2, ...) | 'boolean' | 'other'}
|
||||
# -- totally static, though different between PackDialog and WidgetDialog
|
||||
# (but even that could be unified)
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
class Option:
|
||||
|
||||
varclass = StringVar # May be overridden
|
||||
|
||||
def __init__(self, dialog, option):
|
||||
self.dialog = dialog
|
||||
self.option = option
|
||||
self.master = dialog.top
|
||||
self.default, self.klass = dialog.options[option]
|
||||
self.var = self.varclass(self.master)
|
||||
self.frame = Frame(self.master)
|
||||
self.frame.pack(fill=X)
|
||||
self.label = Label(self.frame, text=(option + ":"))
|
||||
self.label.pack(side=LEFT)
|
||||
self.update()
|
||||
self.addoption()
|
||||
|
||||
def refresh(self):
|
||||
self.dialog.refresh()
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
try:
|
||||
self.current = self.dialog.current[self.option]
|
||||
except KeyError:
|
||||
self.current = self.default
|
||||
self.var.set(self.current)
|
||||
|
||||
def set(self, e=None): # Should be overridden
|
||||
pass
|
||||
|
||||
class BooleanOption(Option):
|
||||
|
||||
varclass = BooleanVar
|
||||
|
||||
def addoption(self):
|
||||
self.button = Checkbutton(self.frame,
|
||||
text='on/off',
|
||||
onvalue=1,
|
||||
offvalue=0,
|
||||
variable=self.var,
|
||||
relief=RAISED,
|
||||
borderwidth=2,
|
||||
command=self.set)
|
||||
self.button.pack(side=RIGHT)
|
||||
|
||||
class EnumOption(Option):
|
||||
|
||||
def addoption(self):
|
||||
self.button = Menubutton(self.frame,
|
||||
textvariable=self.var,
|
||||
relief=RAISED, borderwidth=2)
|
||||
self.button.pack(side=RIGHT)
|
||||
self.menu = Menu(self.button)
|
||||
self.button['menu'] = self.menu
|
||||
for v in self.dialog.classes[self.klass]:
|
||||
self.menu.add_radiobutton(
|
||||
label=v,
|
||||
variable=self.var,
|
||||
value=v,
|
||||
command=self.set)
|
||||
|
||||
class StringOption(Option):
|
||||
|
||||
def addoption(self):
|
||||
self.entry = Entry(self.frame,
|
||||
textvariable=self.var,
|
||||
width=10,
|
||||
relief=SUNKEN,
|
||||
borderwidth=2)
|
||||
self.entry.pack(side=RIGHT, fill=X, expand=1)
|
||||
self.entry.bind('<Return>', self.set)
|
||||
|
||||
class ReadonlyOption(Option):
|
||||
|
||||
def addoption(self):
|
||||
self.label = Label(self.frame, textvariable=self.var,
|
||||
anchor=E)
|
||||
self.label.pack(side=RIGHT)
|
||||
|
||||
class Dialog:
|
||||
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
self.fixclasses()
|
||||
self.refresh()
|
||||
self.top = Toplevel(self.master)
|
||||
self.top.title(self.__class__.__name__)
|
||||
self.top.minsize(1, 1)
|
||||
self.addchoices()
|
||||
|
||||
def refresh(self): pass # Must override
|
||||
|
||||
def fixclasses(self): pass # May override
|
||||
|
||||
def addchoices(self):
|
||||
self.choices = {}
|
||||
list = []
|
||||
for k, dc in self.options.items():
|
||||
list.append((k, dc))
|
||||
list.sort()
|
||||
for k, (d, c) in list:
|
||||
try:
|
||||
cl = self.classes[c]
|
||||
except KeyError:
|
||||
cl = 'unknown'
|
||||
if type(cl) == TupleType:
|
||||
cl = self.enumoption
|
||||
elif cl == 'boolean':
|
||||
cl = self.booleanoption
|
||||
elif cl == 'readonly':
|
||||
cl = self.readonlyoption
|
||||
else:
|
||||
cl = self.stringoption
|
||||
self.choices[k] = cl(self, k)
|
||||
|
||||
# Must override:
|
||||
options = {}
|
||||
classes = {}
|
||||
|
||||
# May override:
|
||||
booleanoption = BooleanOption
|
||||
stringoption = StringOption
|
||||
enumoption = EnumOption
|
||||
readonlyoption = ReadonlyOption
|
||||
|
||||
class PackDialog(Dialog):
|
||||
|
||||
def __init__(self, widget):
|
||||
self.widget = widget
|
||||
Dialog.__init__(self, widget)
|
||||
|
||||
def refresh(self):
|
||||
self.current = self.widget.info()
|
||||
self.current['.class'] = self.widget.winfo_class()
|
||||
self.current['.name'] = self.widget._w
|
||||
|
||||
class packoption: # Mix-in class
|
||||
def set(self, e=None):
|
||||
self.current = self.var.get()
|
||||
try:
|
||||
apply(self.dialog.widget.pack, (),
|
||||
{self.option: self.current})
|
||||
except TclError, msg:
|
||||
print msg
|
||||
self.refresh()
|
||||
|
||||
class booleanoption(packoption, BooleanOption): pass
|
||||
class enumoption(packoption, EnumOption): pass
|
||||
class stringoption(packoption, StringOption): pass
|
||||
class readonlyoption(packoption, ReadonlyOption): pass
|
||||
|
||||
options = {
|
||||
'.class': (None, 'Class'),
|
||||
'.name': (None, 'Name'),
|
||||
'after': (None, 'Widget'),
|
||||
'anchor': ('center', 'Anchor'),
|
||||
'before': (None, 'Widget'),
|
||||
'expand': ('no', 'Boolean'),
|
||||
'fill': ('none', 'Fill'),
|
||||
'in': (None, 'Widget'),
|
||||
'ipadx': (0, 'Pad'),
|
||||
'ipady': (0, 'Pad'),
|
||||
'padx': (0, 'Pad'),
|
||||
'pady': (0, 'Pad'),
|
||||
'side': ('top', 'Side'),
|
||||
}
|
||||
|
||||
classes = {
|
||||
'Anchor': (N, NE, E, SE, S, SW, W, NW, CENTER),
|
||||
'Boolean': 'boolean',
|
||||
'Class': 'readonly',
|
||||
'Expand': 'boolean',
|
||||
'Fill': (NONE, X, Y, BOTH),
|
||||
'Name': 'readonly',
|
||||
'Pad': 'pixel',
|
||||
'Side': (TOP, RIGHT, BOTTOM, LEFT),
|
||||
'Widget': 'readonly',
|
||||
}
|
||||
|
||||
class RemotePackDialog(PackDialog):
|
||||
|
||||
def __init__(self, master, app, widget):
|
||||
self.master = master
|
||||
self.app = app
|
||||
self.widget = widget
|
||||
self.refresh()
|
||||
self.top = Toplevel(self.master)
|
||||
self.top.title(self.app + ' PackDialog')
|
||||
self.top.minsize(1, 1)
|
||||
self.addchoices()
|
||||
|
||||
def refresh(self):
|
||||
try:
|
||||
words = self.master.tk.splitlist(
|
||||
self.master.send(self.app,
|
||||
'pack',
|
||||
'info',
|
||||
self.widget))
|
||||
except TclError, msg:
|
||||
print msg
|
||||
return
|
||||
dict = {}
|
||||
for i in range(0, len(words), 2):
|
||||
key = words[i][1:]
|
||||
value = words[i+1]
|
||||
dict[key] = value
|
||||
dict['.class'] = self.master.send(self.app,
|
||||
'winfo',
|
||||
'class',
|
||||
self.widget)
|
||||
dict['.name'] = self.widget
|
||||
self.current = dict
|
||||
|
||||
class remotepackoption: # Mix-in class
|
||||
def set(self, e=None):
|
||||
self.current = self.var.get()
|
||||
try:
|
||||
self.dialog.master.send(
|
||||
self.dialog.app,
|
||||
'pack',
|
||||
'config',
|
||||
self.dialog.widget,
|
||||
'-'+self.option,
|
||||
self.dialog.master.tk.merge(
|
||||
self.current))
|
||||
except TclError, msg:
|
||||
print msg
|
||||
self.refresh()
|
||||
|
||||
class booleanoption(remotepackoption, BooleanOption): pass
|
||||
class enumoption(remotepackoption, EnumOption): pass
|
||||
class stringoption(remotepackoption, StringOption): pass
|
||||
class readonlyoption(remotepackoption, ReadonlyOption): pass
|
||||
|
||||
class WidgetDialog(Dialog):
|
||||
|
||||
def __init__(self, widget):
|
||||
self.widget = widget
|
||||
self.klass = widget.winfo_class()
|
||||
Dialog.__init__(self, widget)
|
||||
|
||||
def fixclasses(self):
|
||||
if self.addclasses.has_key(self.klass):
|
||||
classes = {}
|
||||
for c in (self.classes,
|
||||
self.addclasses[self.klass]):
|
||||
for k in c.keys():
|
||||
classes[k] = c[k]
|
||||
self.classes = classes
|
||||
|
||||
def refresh(self):
|
||||
self.configuration = self.widget.config()
|
||||
self.update()
|
||||
self.current['.class'] = self.widget.winfo_class()
|
||||
self.current['.name'] = self.widget._w
|
||||
|
||||
def update(self):
|
||||
self.current = {}
|
||||
self.options = {}
|
||||
for k, v in self.configuration.items():
|
||||
if len(v) > 4:
|
||||
self.current[k] = v[4]
|
||||
self.options[k] = v[3], v[2] # default, klass
|
||||
self.options['.class'] = (None, 'Class')
|
||||
self.options['.name'] = (None, 'Name')
|
||||
|
||||
class widgetoption: # Mix-in class
|
||||
def set(self, e=None):
|
||||
self.current = self.var.get()
|
||||
try:
|
||||
self.dialog.widget[self.option] = self.current
|
||||
except TclError, msg:
|
||||
print msg
|
||||
self.refresh()
|
||||
|
||||
class booleanoption(widgetoption, BooleanOption): pass
|
||||
class enumoption(widgetoption, EnumOption): pass
|
||||
class stringoption(widgetoption, StringOption): pass
|
||||
class readonlyoption(widgetoption, ReadonlyOption): pass
|
||||
|
||||
# Universal classes
|
||||
classes = {
|
||||
'Anchor': (N, NE, E, SE, S, SW, W, NW, CENTER),
|
||||
'Aspect': 'integer',
|
||||
'Background': 'color',
|
||||
'Bitmap': 'bitmap',
|
||||
'BorderWidth': 'pixel',
|
||||
'Class': 'readonly',
|
||||
'CloseEnough': 'double',
|
||||
'Command': 'command',
|
||||
'Confine': 'boolean',
|
||||
'Cursor': 'cursor',
|
||||
'CursorWidth': 'pixel',
|
||||
'DisabledForeground': 'color',
|
||||
'ExportSelection': 'boolean',
|
||||
'Font': 'font',
|
||||
'Foreground': 'color',
|
||||
'From': 'integer',
|
||||
'Geometry': 'geometry',
|
||||
'Height': 'pixel',
|
||||
'InsertWidth': 'time',
|
||||
'Justify': (LEFT, CENTER, RIGHT),
|
||||
'Label': 'string',
|
||||
'Length': 'pixel',
|
||||
'MenuName': 'widget',
|
||||
'Name': 'readonly',
|
||||
'OffTime': 'time',
|
||||
'OnTime': 'time',
|
||||
'Orient': (HORIZONTAL, VERTICAL),
|
||||
'Pad': 'pixel',
|
||||
'Relief': (RAISED, SUNKEN, FLAT, RIDGE, GROOVE),
|
||||
'RepeatDelay': 'time',
|
||||
'RepeatInterval': 'time',
|
||||
'ScrollCommand': 'command',
|
||||
'ScrollIncrement': 'pixel',
|
||||
'ScrollRegion': 'rectangle',
|
||||
'ShowValue': 'boolean',
|
||||
'SetGrid': 'boolean',
|
||||
'Sliderforeground': 'color',
|
||||
'SliderLength': 'pixel',
|
||||
'Text': 'string',
|
||||
'TickInterval': 'integer',
|
||||
'To': 'integer',
|
||||
'Underline': 'index',
|
||||
'Variable': 'variable',
|
||||
'Value': 'string',
|
||||
'Width': 'pixel',
|
||||
'Wrap': (NONE, CHAR, WORD),
|
||||
}
|
||||
|
||||
# Classes that (may) differ per widget type
|
||||
_tristate = {'State': (NORMAL, ACTIVE, DISABLED)}
|
||||
_bistate = {'State': (NORMAL, DISABLED)}
|
||||
addclasses = {
|
||||
'Button': _tristate,
|
||||
'Radiobutton': _tristate,
|
||||
'Checkbutton': _tristate,
|
||||
'Entry': _bistate,
|
||||
'Text': _bistate,
|
||||
'Menubutton': _tristate,
|
||||
'Slider': _bistate,
|
||||
}
|
||||
|
||||
class RemoteWidgetDialog(WidgetDialog):
|
||||
|
||||
def __init__(self, master, app, widget):
|
||||
self.app = app
|
||||
self.widget = widget
|
||||
self.klass = master.send(self.app,
|
||||
'winfo',
|
||||
'class',
|
||||
self.widget)
|
||||
Dialog.__init__(self, master)
|
||||
|
||||
def refresh(self):
|
||||
try:
|
||||
items = self.master.tk.splitlist(
|
||||
self.master.send(self.app,
|
||||
self.widget,
|
||||
'config'))
|
||||
except TclError, msg:
|
||||
print msg
|
||||
return
|
||||
dict = {}
|
||||
for item in items:
|
||||
words = self.master.tk.splitlist(item)
|
||||
key = words[0][1:]
|
||||
value = (key,) + words[1:]
|
||||
dict[key] = value
|
||||
self.configuration = dict
|
||||
self.update()
|
||||
self.current['.class'] = self.klass
|
||||
self.current['.name'] = self.widget
|
||||
|
||||
class remotewidgetoption: # Mix-in class
|
||||
def set(self, e=None):
|
||||
self.current = self.var.get()
|
||||
try:
|
||||
self.dialog.master.send(
|
||||
self.dialog.app,
|
||||
self.dialog.widget,
|
||||
'config',
|
||||
'-'+self.option,
|
||||
self.current)
|
||||
except TclError, msg:
|
||||
print msg
|
||||
self.refresh()
|
||||
|
||||
class booleanoption(remotewidgetoption, BooleanOption): pass
|
||||
class enumoption(remotewidgetoption, EnumOption): pass
|
||||
class stringoption(remotewidgetoption, StringOption): pass
|
||||
class readonlyoption(remotewidgetoption, ReadonlyOption): pass
|
||||
|
||||
def test():
|
||||
import sys
|
||||
root = Tk()
|
||||
root.minsize(1, 1)
|
||||
if sys.argv[1:]:
|
||||
remotetest(root, sys.argv[1])
|
||||
else:
|
||||
frame = Frame(root, name='frame')
|
||||
frame.pack(expand=1, fill=BOTH)
|
||||
button = Button(frame, name='button', text='button')
|
||||
button.pack(expand=1)
|
||||
canvas = Canvas(frame, name='canvas')
|
||||
canvas.pack()
|
||||
fpd = PackDialog(frame)
|
||||
fwd = WidgetDialog(frame)
|
||||
bpd = PackDialog(button)
|
||||
bwd = WidgetDialog(button)
|
||||
cpd = PackDialog(canvas)
|
||||
cwd = WidgetDialog(canvas)
|
||||
root.mainloop()
|
||||
|
||||
def remotetest(root, app):
|
||||
from listtree import listtree
|
||||
list = listtree(root, app)
|
||||
list.bind('<Any-Double-1>', opendialogs)
|
||||
list.app = app # Pass it on to handler
|
||||
|
||||
def opendialogs(e):
|
||||
import string
|
||||
list = e.widget
|
||||
sel = list.curselection()
|
||||
for i in sel:
|
||||
item = list.get(i)
|
||||
widget = string.split(item)[0]
|
||||
RemoteWidgetDialog(list, list.app, widget)
|
||||
if widget == '.': continue
|
||||
try:
|
||||
RemotePackDialog(list, list.app, widget)
|
||||
except TclError, msg:
|
||||
print msg
|
||||
|
||||
test()
|
||||
220
Demo/tkinter/guido/ManPage.py
Normal file
220
Demo/tkinter/guido/ManPage.py
Normal file
@@ -0,0 +1,220 @@
|
||||
# Widget to display a man page
|
||||
|
||||
import re
|
||||
from Tkinter import *
|
||||
from Tkinter import _tkinter
|
||||
from ScrolledText import ScrolledText
|
||||
|
||||
# XXX These fonts may have to be changed to match your system
|
||||
BOLDFONT = '*-Courier-Bold-R-Normal-*-120-*'
|
||||
ITALICFONT = '*-Courier-Medium-O-Normal-*-120-*'
|
||||
|
||||
# XXX Recognizing footers is system dependent
|
||||
# (This one works for IRIX 5.2 and Solaris 2.2)
|
||||
footerprog = re.compile(
|
||||
'^ Page [1-9][0-9]*[ \t]+\|^.*Last change:.*[1-9][0-9]*\n')
|
||||
emptyprog = re.compile('^[ \t]*\n')
|
||||
ulprog = re.compile('^[ \t]*[Xv!_][Xv!_ \t]*\n')
|
||||
|
||||
# Basic Man Page class -- does not disable editing
|
||||
class EditableManPage(ScrolledText):
|
||||
|
||||
# Initialize instance
|
||||
def __init__(self, master=None, **cnf):
|
||||
# Initialize base class
|
||||
apply(ScrolledText.__init__, (self, master), cnf)
|
||||
|
||||
# Define tags for formatting styles
|
||||
self.tag_config('X', underline=1)
|
||||
self.tag_config('!', font=BOLDFONT)
|
||||
self.tag_config('_', font=ITALICFONT)
|
||||
|
||||
# Set state to idle
|
||||
self.fp = None
|
||||
self.lineno = 0
|
||||
|
||||
# Test whether we are busy parsing a file
|
||||
def busy(self):
|
||||
return self.fp != None
|
||||
|
||||
# Ensure we're not busy
|
||||
def kill(self):
|
||||
if self.busy():
|
||||
self._endparser()
|
||||
|
||||
# Parse a file, in the background
|
||||
def asyncparsefile(self, fp):
|
||||
self._startparser(fp)
|
||||
self.tk.createfilehandler(fp, _tkinter.READABLE,
|
||||
self._filehandler)
|
||||
|
||||
parsefile = asyncparsefile # Alias
|
||||
|
||||
# I/O handler used by background parsing
|
||||
def _filehandler(self, fp, mask):
|
||||
nextline = self.fp.readline()
|
||||
if not nextline:
|
||||
self._endparser()
|
||||
return
|
||||
self._parseline(nextline)
|
||||
|
||||
# Parse a file, now (cannot be aborted)
|
||||
def syncparsefile(self, fp):
|
||||
from select import select
|
||||
def avail(fp=fp, tout=0.0, select=select):
|
||||
return select([fp], [], [], tout)[0]
|
||||
height = self.getint(self['height'])
|
||||
self._startparser(fp)
|
||||
while 1:
|
||||
nextline = fp.readline()
|
||||
if not nextline:
|
||||
break
|
||||
self._parseline(nextline)
|
||||
self._endparser()
|
||||
|
||||
# Initialize parsing from a particular file -- must not be busy
|
||||
def _startparser(self, fp):
|
||||
if self.busy():
|
||||
raise RuntimeError, 'startparser: still busy'
|
||||
fp.fileno() # Test for file-ness
|
||||
self.fp = fp
|
||||
self.lineno = 0
|
||||
self.ok = 0
|
||||
self.empty = 0
|
||||
self.buffer = None
|
||||
savestate = self['state']
|
||||
self['state'] = NORMAL
|
||||
self.delete('1.0', END)
|
||||
self['state'] = savestate
|
||||
|
||||
# End parsing -- must be busy, need not be at EOF
|
||||
def _endparser(self):
|
||||
if not self.busy():
|
||||
raise RuntimeError, 'endparser: not busy'
|
||||
if self.buffer:
|
||||
self._parseline('')
|
||||
try:
|
||||
self.tk.deletefilehandler(self.fp)
|
||||
except TclError, msg:
|
||||
pass
|
||||
self.fp.close()
|
||||
self.fp = None
|
||||
del self.ok, self.empty, self.buffer
|
||||
|
||||
# Parse a single line
|
||||
def _parseline(self, nextline):
|
||||
if not self.buffer:
|
||||
# Save this line -- we need one line read-ahead
|
||||
self.buffer = nextline
|
||||
return
|
||||
if emptyprog.match(self.buffer) >= 0:
|
||||
# Buffered line was empty -- set a flag
|
||||
self.empty = 1
|
||||
self.buffer = nextline
|
||||
return
|
||||
textline = self.buffer
|
||||
if ulprog.match(nextline) >= 0:
|
||||
# Next line is properties for buffered line
|
||||
propline = nextline
|
||||
self.buffer = None
|
||||
else:
|
||||
# Next line is read-ahead
|
||||
propline = None
|
||||
self.buffer = nextline
|
||||
if not self.ok:
|
||||
# First non blank line after footer must be header
|
||||
# -- skip that too
|
||||
self.ok = 1
|
||||
self.empty = 0
|
||||
return
|
||||
if footerprog.match(textline) >= 0:
|
||||
# Footer -- start skipping until next non-blank line
|
||||
self.ok = 0
|
||||
self.empty = 0
|
||||
return
|
||||
savestate = self['state']
|
||||
self['state'] = NORMAL
|
||||
if TkVersion >= 4.0:
|
||||
self.mark_set('insert', 'end-1c')
|
||||
else:
|
||||
self.mark_set('insert', END)
|
||||
if self.empty:
|
||||
# One or more previous lines were empty
|
||||
# -- insert one blank line in the text
|
||||
self._insert_prop('\n')
|
||||
self.lineno = self.lineno + 1
|
||||
self.empty = 0
|
||||
if not propline:
|
||||
# No properties
|
||||
self._insert_prop(textline)
|
||||
else:
|
||||
# Search for properties
|
||||
p = ''
|
||||
j = 0
|
||||
for i in range(min(len(propline), len(textline))):
|
||||
if propline[i] != p:
|
||||
if j < i:
|
||||
self._insert_prop(textline[j:i], p)
|
||||
j = i
|
||||
p = propline[i]
|
||||
self._insert_prop(textline[j:])
|
||||
self.lineno = self.lineno + 1
|
||||
self['state'] = savestate
|
||||
|
||||
# Insert a string at the end, with at most one property (tag)
|
||||
def _insert_prop(self, str, prop = ' '):
|
||||
here = self.index(AtInsert())
|
||||
self.insert(AtInsert(), str)
|
||||
if TkVersion <= 4.0:
|
||||
tags = self.tag_names(here)
|
||||
for tag in tags:
|
||||
self.tag_remove(tag, here, AtInsert())
|
||||
if prop != ' ':
|
||||
self.tag_add(prop, here, AtInsert())
|
||||
|
||||
# Readonly Man Page class -- disables editing, otherwise the same
|
||||
class ReadonlyManPage(EditableManPage):
|
||||
|
||||
# Initialize instance
|
||||
def __init__(self, master=None, **cnf):
|
||||
cnf['state'] = DISABLED
|
||||
apply(EditableManPage.__init__, (self, master), cnf)
|
||||
|
||||
# Alias
|
||||
ManPage = ReadonlyManPage
|
||||
|
||||
# Test program.
|
||||
# usage: ManPage [manpage]; or ManPage [-f] file
|
||||
# -f means that the file is nroff -man output run through ul -i
|
||||
def test():
|
||||
import os
|
||||
import sys
|
||||
# XXX This directory may be different on your system
|
||||
MANDIR = '/usr/local/man/mann'
|
||||
DEFAULTPAGE = 'Tcl'
|
||||
formatted = 0
|
||||
if sys.argv[1:] and sys.argv[1] == '-f':
|
||||
formatted = 1
|
||||
del sys.argv[1]
|
||||
if sys.argv[1:]:
|
||||
name = sys.argv[1]
|
||||
else:
|
||||
name = DEFAULTPAGE
|
||||
if not formatted:
|
||||
if name[-2:-1] != '.':
|
||||
name = name + '.n'
|
||||
name = os.path.join(MANDIR, name)
|
||||
root = Tk()
|
||||
root.minsize(1, 1)
|
||||
manpage = ManPage(root, relief=SUNKEN, borderwidth=2)
|
||||
manpage.pack(expand=1, fill=BOTH)
|
||||
if formatted:
|
||||
fp = open(name, 'r')
|
||||
else:
|
||||
fp = os.popen('nroff -man %s | ul -i' % name, 'r')
|
||||
manpage.parsefile(fp)
|
||||
root.mainloop()
|
||||
|
||||
# Run the test program when called as a script
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
143
Demo/tkinter/guido/MimeViewer.py
Executable file
143
Demo/tkinter/guido/MimeViewer.py
Executable file
@@ -0,0 +1,143 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# View a single MIME multipart message.
|
||||
# Display each part as a box.
|
||||
|
||||
import string
|
||||
from types import *
|
||||
from Tkinter import *
|
||||
from ScrolledText import ScrolledText
|
||||
|
||||
class MimeViewer:
|
||||
def __init__(self, parent, title, msg):
|
||||
self.title = title
|
||||
self.msg = msg
|
||||
self.frame = Frame(parent, {'relief': 'raised', 'bd': 2})
|
||||
self.frame.packing = {'expand': 0, 'fill': 'both'}
|
||||
self.button = Checkbutton(self.frame,
|
||||
{'text': title,
|
||||
'command': self.toggle})
|
||||
self.button.pack({'anchor': 'w'})
|
||||
headertext = msg.getheadertext(
|
||||
lambda x: x != 'received' and x[:5] != 'x400-')
|
||||
height = countlines(headertext, 4)
|
||||
if height:
|
||||
self.htext = ScrolledText(self.frame,
|
||||
{'height': height,
|
||||
'width': 80,
|
||||
'wrap': 'none',
|
||||
'relief': 'raised',
|
||||
'bd': 2})
|
||||
self.htext.packing = {'expand': 1, 'fill': 'both',
|
||||
'after': self.button}
|
||||
self.htext.insert('end', headertext)
|
||||
else:
|
||||
self.htext = Frame(self.frame,
|
||||
{'relief': 'raised', 'bd': 2})
|
||||
self.htext.packing = {'side': 'top',
|
||||
'ipady': 2,
|
||||
'fill': 'x',
|
||||
'after': self.button}
|
||||
body = msg.getbody()
|
||||
if type(body) == StringType:
|
||||
self.pad = None
|
||||
height = countlines(body, 10)
|
||||
if height:
|
||||
self.btext = ScrolledText(self.frame,
|
||||
{'height': height,
|
||||
'width': 80,
|
||||
'wrap': 'none',
|
||||
'relief': 'raised',
|
||||
'bd': 2})
|
||||
self.btext.packing = {'expand': 1,
|
||||
'fill': 'both'}
|
||||
self.btext.insert('end', body)
|
||||
else:
|
||||
self.btext = None
|
||||
self.parts = None
|
||||
else:
|
||||
self.pad = Frame(self.frame,
|
||||
{'relief': 'flat', 'bd': 2})
|
||||
self.pad.packing = {'side': 'left', 'ipadx': 10,
|
||||
'fill': 'y', 'after': self.htext}
|
||||
self.parts = []
|
||||
for i in range(len(body)):
|
||||
p = MimeViewer(self.frame,
|
||||
'%s.%d' % (title, i+1),
|
||||
body[i])
|
||||
self.parts.append(p)
|
||||
self.btext = None
|
||||
self.collapsed = 1
|
||||
def pack(self):
|
||||
self.frame.pack(self.frame.packing)
|
||||
def destroy(self):
|
||||
self.frame.destroy()
|
||||
def show(self):
|
||||
if self.collapsed:
|
||||
self.button.invoke()
|
||||
def toggle(self):
|
||||
if self.collapsed:
|
||||
self.explode()
|
||||
else:
|
||||
self.collapse()
|
||||
def collapse(self):
|
||||
self.collapsed = 1
|
||||
for comp in self.htext, self.btext, self.pad:
|
||||
if comp:
|
||||
comp.forget()
|
||||
if self.parts:
|
||||
for part in self.parts:
|
||||
part.frame.forget()
|
||||
self.frame.pack({'expand': 0})
|
||||
def explode(self):
|
||||
self.collapsed = 0
|
||||
for comp in self.htext, self.btext, self.pad:
|
||||
if comp: comp.pack(comp.packing)
|
||||
if self.parts:
|
||||
for part in self.parts:
|
||||
part.pack()
|
||||
self.frame.pack({'expand': 1})
|
||||
|
||||
def countlines(str, limit):
|
||||
i = 0
|
||||
n = 0
|
||||
while n < limit:
|
||||
i = string.find(str, '\n', i)
|
||||
if i < 0: break
|
||||
n = n+1
|
||||
i = i+1
|
||||
return n
|
||||
|
||||
def main():
|
||||
import sys
|
||||
import getopt
|
||||
import mhlib
|
||||
opts, args = getopt.getopt(sys.argv[1:], '')
|
||||
for o, a in opts:
|
||||
pass
|
||||
message = None
|
||||
folder = 'inbox'
|
||||
for arg in args:
|
||||
if arg[:1] == '+':
|
||||
folder = arg[1:]
|
||||
else:
|
||||
message = string.atoi(arg)
|
||||
|
||||
mh = mhlib.MH()
|
||||
f = mh.openfolder(folder)
|
||||
if not message:
|
||||
message = f.getcurrent()
|
||||
m = f.openmessage(message)
|
||||
|
||||
root = Tk()
|
||||
tk = root.tk
|
||||
|
||||
top = MimeViewer(root, '+%s/%d' % (folder, message), m)
|
||||
top.pack()
|
||||
top.show()
|
||||
|
||||
root.minsize(1, 1)
|
||||
|
||||
tk.mainloop()
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
147
Demo/tkinter/guido/ShellWindow.py
Normal file
147
Demo/tkinter/guido/ShellWindow.py
Normal file
@@ -0,0 +1,147 @@
|
||||
import os
|
||||
import sys
|
||||
import string
|
||||
from Tkinter import *
|
||||
from ScrolledText import ScrolledText
|
||||
from Dialog import Dialog
|
||||
import signal
|
||||
|
||||
BUFSIZE = 512
|
||||
|
||||
class ShellWindow(ScrolledText):
|
||||
|
||||
def __init__(self, master=None, shell=None, **cnf):
|
||||
if not shell:
|
||||
try:
|
||||
shell = os.environ['SHELL']
|
||||
except KeyError:
|
||||
shell = '/bin/sh'
|
||||
shell = shell + ' -i'
|
||||
args = string.split(shell)
|
||||
shell = args[0]
|
||||
|
||||
apply(ScrolledText.__init__, (self, master), cnf)
|
||||
self.pos = '1.0'
|
||||
self.bind('<Return>', self.inputhandler)
|
||||
self.bind('<Control-c>', self.sigint)
|
||||
self.bind('<Control-t>', self.sigterm)
|
||||
self.bind('<Control-k>', self.sigkill)
|
||||
self.bind('<Control-d>', self.sendeof)
|
||||
|
||||
self.pid, self.fromchild, self.tochild = spawn(shell, args)
|
||||
self.tk.createfilehandler(self.fromchild, READABLE,
|
||||
self.outputhandler)
|
||||
|
||||
def outputhandler(self, file, mask):
|
||||
data = os.read(file, BUFSIZE)
|
||||
if not data:
|
||||
self.tk.deletefilehandler(file)
|
||||
pid, sts = os.waitpid(self.pid, 0)
|
||||
print 'pid', pid, 'status', sts
|
||||
self.pid = None
|
||||
detail = sts>>8
|
||||
cause = sts & 0xff
|
||||
if cause == 0:
|
||||
msg = "exit status %d" % detail
|
||||
else:
|
||||
msg = "killed by signal %d" % (cause & 0x7f)
|
||||
if cause & 0x80:
|
||||
msg = msg + " -- core dumped"
|
||||
Dialog(self.master,
|
||||
text=msg,
|
||||
title="Exit status",
|
||||
bitmap='warning',
|
||||
default=0,
|
||||
strings=('OK',))
|
||||
return
|
||||
self.insert(END, data)
|
||||
self.pos = self.index("end - 1 char")
|
||||
self.yview_pickplace(END)
|
||||
|
||||
def inputhandler(self, *args):
|
||||
if not self.pid:
|
||||
self.no_process()
|
||||
return "break"
|
||||
self.insert(END, "\n")
|
||||
line = self.get(self.pos, "end - 1 char")
|
||||
self.pos = self.index(END)
|
||||
os.write(self.tochild, line)
|
||||
return "break"
|
||||
|
||||
def sendeof(self, *args):
|
||||
if not self.pid:
|
||||
self.no_process()
|
||||
return "break"
|
||||
os.close(self.tochild)
|
||||
return "break"
|
||||
|
||||
def sendsig(self, sig):
|
||||
if not self.pid:
|
||||
self.no_process()
|
||||
return "break"
|
||||
os.kill(self.pid, sig)
|
||||
return "break"
|
||||
|
||||
def sigint(self, *args):
|
||||
return self.sendsig(signal.SIGINT)
|
||||
|
||||
def sigquit(self, *args):
|
||||
return self.sendsig(signal.SIGQUIT)
|
||||
|
||||
def sigterm(self, *args):
|
||||
return self.sendsig(signal.SIGTERM)
|
||||
|
||||
def sigkill(self, *args):
|
||||
return self.sendsig(signal.SIGKILL)
|
||||
|
||||
def no_process(self):
|
||||
Dialog(self.master,
|
||||
text="No active process",
|
||||
title="No process",
|
||||
bitmap='error',
|
||||
default=0,
|
||||
strings=('OK',))
|
||||
|
||||
MAXFD = 100 # Max number of file descriptors (os.getdtablesize()???)
|
||||
|
||||
def spawn(prog, args):
|
||||
p2cread, p2cwrite = os.pipe()
|
||||
c2pread, c2pwrite = os.pipe()
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
# Child
|
||||
for i in 0, 1, 2:
|
||||
try:
|
||||
os.close(i)
|
||||
except os.error:
|
||||
pass
|
||||
if os.dup(p2cread) <> 0:
|
||||
sys.stderr.write('popen2: bad read dup\n')
|
||||
if os.dup(c2pwrite) <> 1:
|
||||
sys.stderr.write('popen2: bad write dup\n')
|
||||
if os.dup(c2pwrite) <> 2:
|
||||
sys.stderr.write('popen2: bad write dup\n')
|
||||
os.closerange(3, MAXFD)
|
||||
try:
|
||||
os.execvp(prog, args)
|
||||
finally:
|
||||
sys.stderr.write('execvp failed\n')
|
||||
os._exit(1)
|
||||
os.close(p2cread)
|
||||
os.close(c2pwrite)
|
||||
return pid, c2pread, p2cwrite
|
||||
|
||||
def test():
|
||||
shell = string.join(sys.argv[1:])
|
||||
root = Tk()
|
||||
root.minsize(1, 1)
|
||||
if shell:
|
||||
w = ShellWindow(root, shell=shell)
|
||||
else:
|
||||
w = ShellWindow(root)
|
||||
w.pack(expand=1, fill=BOTH)
|
||||
w.focus_set()
|
||||
w.tk.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
50
Demo/tkinter/guido/brownian.py
Normal file
50
Demo/tkinter/guido/brownian.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# Brownian motion -- an example of a multi-threaded Tkinter program.
|
||||
|
||||
from Tkinter import *
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
import sys
|
||||
|
||||
WIDTH = 400
|
||||
HEIGHT = 300
|
||||
SIGMA = 10
|
||||
BUZZ = 2
|
||||
RADIUS = 2
|
||||
LAMBDA = 10
|
||||
FILL = 'red'
|
||||
|
||||
stop = 0 # Set when main loop exits
|
||||
|
||||
def particle(canvas):
|
||||
r = RADIUS
|
||||
x = random.gauss(WIDTH/2.0, SIGMA)
|
||||
y = random.gauss(HEIGHT/2.0, SIGMA)
|
||||
p = canvas.create_oval(x-r, y-r, x+r, y+r, fill=FILL)
|
||||
while not stop:
|
||||
dx = random.gauss(0, BUZZ)
|
||||
dy = random.gauss(0, BUZZ)
|
||||
dt = random.expovariate(LAMBDA)
|
||||
try:
|
||||
canvas.move(p, dx, dy)
|
||||
except TclError:
|
||||
break
|
||||
time.sleep(dt)
|
||||
|
||||
def main():
|
||||
global stop
|
||||
root = Tk()
|
||||
canvas = Canvas(root, width=WIDTH, height=HEIGHT)
|
||||
canvas.pack(fill='both', expand=1)
|
||||
np = 30
|
||||
if sys.argv[1:]:
|
||||
np = int(sys.argv[1])
|
||||
for i in range(np):
|
||||
t = threading.Thread(target=particle, args=(canvas,))
|
||||
t.start()
|
||||
try:
|
||||
root.mainloop()
|
||||
finally:
|
||||
stop = 1
|
||||
|
||||
main()
|
||||
55
Demo/tkinter/guido/brownian2.py
Normal file
55
Demo/tkinter/guido/brownian2.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# Brownian motion -- an example of a NON multi-threaded Tkinter program ;)
|
||||
# By Michele Simoniato, inspired by brownian.py
|
||||
|
||||
from Tkinter import *
|
||||
import random
|
||||
import sys
|
||||
|
||||
WIDTH = 400
|
||||
HEIGHT = 300
|
||||
SIGMA = 10
|
||||
BUZZ = 2
|
||||
RADIUS = 2
|
||||
LAMBDA = 10
|
||||
FILL = 'red'
|
||||
|
||||
stop = 0 # Set when main loop exits
|
||||
root = None # main window
|
||||
|
||||
def particle(canvas): # particle = iterator over the moves
|
||||
r = RADIUS
|
||||
x = random.gauss(WIDTH/2.0, SIGMA)
|
||||
y = random.gauss(HEIGHT/2.0, SIGMA)
|
||||
p = canvas.create_oval(x-r, y-r, x+r, y+r, fill=FILL)
|
||||
while not stop:
|
||||
dx = random.gauss(0, BUZZ)
|
||||
dy = random.gauss(0, BUZZ)
|
||||
try:
|
||||
canvas.move(p, dx, dy)
|
||||
except TclError:
|
||||
break
|
||||
else:
|
||||
yield None
|
||||
|
||||
def move(particle): # move the particle at random time
|
||||
particle.next()
|
||||
dt = random.expovariate(LAMBDA)
|
||||
root.after(int(dt*1000), move, particle)
|
||||
|
||||
def main():
|
||||
global root, stop
|
||||
root = Tk()
|
||||
canvas = Canvas(root, width=WIDTH, height=HEIGHT)
|
||||
canvas.pack(fill='both', expand=1)
|
||||
np = 30
|
||||
if sys.argv[1:]:
|
||||
np = int(sys.argv[1])
|
||||
for i in range(np): # start the dance
|
||||
move(particle(canvas))
|
||||
try:
|
||||
root.mainloop()
|
||||
finally:
|
||||
stop = 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
244
Demo/tkinter/guido/canvasevents.py
Executable file
244
Demo/tkinter/guido/canvasevents.py
Executable file
@@ -0,0 +1,244 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
from Tkinter import *
|
||||
from Canvas import Oval, Group, CanvasText
|
||||
|
||||
|
||||
# Fix a bug in Canvas.Group as distributed in Python 1.4. The
|
||||
# distributed bind() method is broken. This is what should be used:
|
||||
|
||||
class Group(Group):
|
||||
def bind(self, sequence=None, command=None):
|
||||
return self.canvas.tag_bind(self.id, sequence, command)
|
||||
|
||||
class Object:
|
||||
|
||||
"""Base class for composite graphical objects.
|
||||
|
||||
Objects belong to a canvas, and can be moved around on the canvas.
|
||||
They also belong to at most one ``pile'' of objects, and can be
|
||||
transferred between piles (or removed from their pile).
|
||||
|
||||
Objects have a canonical ``x, y'' position which is moved when the
|
||||
object is moved. Where the object is relative to this position
|
||||
depends on the object; for simple objects, it may be their center.
|
||||
|
||||
Objects have mouse sensitivity. They can be clicked, dragged and
|
||||
double-clicked. The behavior may actually be determined by the pile
|
||||
they are in.
|
||||
|
||||
All instance attributes are public since the derived class may
|
||||
need them.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, canvas, x=0, y=0, fill='red', text='object'):
|
||||
self.canvas = canvas
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.pile = None
|
||||
self.group = Group(self.canvas)
|
||||
self.createitems(fill, text)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.group)
|
||||
|
||||
def createitems(self, fill, text):
|
||||
self.__oval = Oval(self.canvas,
|
||||
self.x-20, self.y-10, self.x+20, self.y+10,
|
||||
fill=fill, width=3)
|
||||
self.group.addtag_withtag(self.__oval)
|
||||
self.__text = CanvasText(self.canvas,
|
||||
self.x, self.y, text=text)
|
||||
self.group.addtag_withtag(self.__text)
|
||||
|
||||
def moveby(self, dx, dy):
|
||||
if dx == dy == 0:
|
||||
return
|
||||
self.group.move(dx, dy)
|
||||
self.x = self.x + dx
|
||||
self.y = self.y + dy
|
||||
|
||||
def moveto(self, x, y):
|
||||
self.moveby(x - self.x, y - self.y)
|
||||
|
||||
def transfer(self, pile):
|
||||
if self.pile:
|
||||
self.pile.delete(self)
|
||||
self.pile = None
|
||||
self.pile = pile
|
||||
if self.pile:
|
||||
self.pile.add(self)
|
||||
|
||||
def tkraise(self):
|
||||
self.group.tkraise()
|
||||
|
||||
|
||||
class Bottom(Object):
|
||||
|
||||
"""An object to serve as the bottom of a pile."""
|
||||
|
||||
def createitems(self, *args):
|
||||
self.__oval = Oval(self.canvas,
|
||||
self.x-20, self.y-10, self.x+20, self.y+10,
|
||||
fill='gray', outline='')
|
||||
self.group.addtag_withtag(self.__oval)
|
||||
|
||||
|
||||
class Pile:
|
||||
|
||||
"""A group of graphical objects."""
|
||||
|
||||
def __init__(self, canvas, x, y, tag=None):
|
||||
self.canvas = canvas
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.objects = []
|
||||
self.bottom = Bottom(self.canvas, self.x, self.y)
|
||||
self.group = Group(self.canvas, tag=tag)
|
||||
self.group.addtag_withtag(self.bottom.group)
|
||||
self.bindhandlers()
|
||||
|
||||
def bindhandlers(self):
|
||||
self.group.bind('<1>', self.clickhandler)
|
||||
self.group.bind('<Double-1>', self.doubleclickhandler)
|
||||
|
||||
def add(self, object):
|
||||
self.objects.append(object)
|
||||
self.group.addtag_withtag(object.group)
|
||||
self.position(object)
|
||||
|
||||
def delete(self, object):
|
||||
object.group.dtag(self.group)
|
||||
self.objects.remove(object)
|
||||
|
||||
def position(self, object):
|
||||
object.tkraise()
|
||||
i = self.objects.index(object)
|
||||
object.moveto(self.x + i*4, self.y + i*8)
|
||||
|
||||
def clickhandler(self, event):
|
||||
pass
|
||||
|
||||
def doubleclickhandler(self, event):
|
||||
pass
|
||||
|
||||
|
||||
class MovingPile(Pile):
|
||||
|
||||
def bindhandlers(self):
|
||||
Pile.bindhandlers(self)
|
||||
self.group.bind('<B1-Motion>', self.motionhandler)
|
||||
self.group.bind('<ButtonRelease-1>', self.releasehandler)
|
||||
|
||||
movethis = None
|
||||
|
||||
def clickhandler(self, event):
|
||||
tags = self.canvas.gettags('current')
|
||||
for i in range(len(self.objects)):
|
||||
o = self.objects[i]
|
||||
if o.group.tag in tags:
|
||||
break
|
||||
else:
|
||||
self.movethis = None
|
||||
return
|
||||
self.movethis = self.objects[i:]
|
||||
for o in self.movethis:
|
||||
o.tkraise()
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
doubleclickhandler = clickhandler
|
||||
|
||||
def motionhandler(self, event):
|
||||
if not self.movethis:
|
||||
return
|
||||
dx = event.x - self.lastx
|
||||
dy = event.y - self.lasty
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
for o in self.movethis:
|
||||
o.moveby(dx, dy)
|
||||
|
||||
def releasehandler(self, event):
|
||||
objects = self.movethis
|
||||
if not objects:
|
||||
return
|
||||
self.movethis = None
|
||||
self.finishmove(objects)
|
||||
|
||||
def finishmove(self, objects):
|
||||
for o in objects:
|
||||
self.position(o)
|
||||
|
||||
|
||||
class Pile1(MovingPile):
|
||||
|
||||
x = 50
|
||||
y = 50
|
||||
tag = 'p1'
|
||||
|
||||
def __init__(self, demo):
|
||||
self.demo = demo
|
||||
MovingPile.__init__(self, self.demo.canvas, self.x, self.y, self.tag)
|
||||
|
||||
def doubleclickhandler(self, event):
|
||||
try:
|
||||
o = self.objects[-1]
|
||||
except IndexError:
|
||||
return
|
||||
o.transfer(self.other())
|
||||
MovingPile.doubleclickhandler(self, event)
|
||||
|
||||
def other(self):
|
||||
return self.demo.p2
|
||||
|
||||
def finishmove(self, objects):
|
||||
o = objects[0]
|
||||
p = self.other()
|
||||
x, y = o.x, o.y
|
||||
if (x-p.x)**2 + (y-p.y)**2 < (x-self.x)**2 + (y-self.y)**2:
|
||||
for o in objects:
|
||||
o.transfer(p)
|
||||
else:
|
||||
MovingPile.finishmove(self, objects)
|
||||
|
||||
class Pile2(Pile1):
|
||||
|
||||
x = 150
|
||||
y = 50
|
||||
tag = 'p2'
|
||||
|
||||
def other(self):
|
||||
return self.demo.p1
|
||||
|
||||
|
||||
class Demo:
|
||||
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
self.canvas = Canvas(master,
|
||||
width=200, height=200,
|
||||
background='yellow',
|
||||
relief=SUNKEN, borderwidth=2)
|
||||
self.canvas.pack(expand=1, fill=BOTH)
|
||||
self.p1 = Pile1(self)
|
||||
self.p2 = Pile2(self)
|
||||
o1 = Object(self.canvas, fill='red', text='o1')
|
||||
o2 = Object(self.canvas, fill='green', text='o2')
|
||||
o3 = Object(self.canvas, fill='light blue', text='o3')
|
||||
o1.transfer(self.p1)
|
||||
o2.transfer(self.p1)
|
||||
o3.transfer(self.p2)
|
||||
|
||||
|
||||
# Main function, run when invoked as a stand-alone Python program.
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
demo = Demo(root)
|
||||
root.protocol('WM_DELETE_WINDOW', root.quit)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
109
Demo/tkinter/guido/dialog.py
Executable file
109
Demo/tkinter/guido/dialog.py
Executable file
@@ -0,0 +1,109 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# A Python function that generates dialog boxes with a text message,
|
||||
# optional bitmap, and any number of buttons.
|
||||
# Cf. Ousterhout, Tcl and the Tk Toolkit, Figs. 27.2-3, pp. 269-270.
|
||||
|
||||
from Tkinter import *
|
||||
import sys
|
||||
|
||||
|
||||
def dialog(master, title, text, bitmap, default, *args):
|
||||
|
||||
# 1. Create the top-level window and divide it into top
|
||||
# and bottom parts.
|
||||
|
||||
w = Toplevel(master, class_='Dialog')
|
||||
w.title(title)
|
||||
w.iconname('Dialog')
|
||||
|
||||
top = Frame(w, relief=RAISED, borderwidth=1)
|
||||
top.pack(side=TOP, fill=BOTH)
|
||||
bot = Frame(w, relief=RAISED, borderwidth=1)
|
||||
bot.pack(side=BOTTOM, fill=BOTH)
|
||||
|
||||
# 2. Fill the top part with the bitmap and message.
|
||||
|
||||
msg = Message(top, width='3i', text=text,
|
||||
font='-Adobe-Times-Medium-R-Normal-*-180-*')
|
||||
msg.pack(side=RIGHT, expand=1, fill=BOTH, padx='3m', pady='3m')
|
||||
if bitmap:
|
||||
bm = Label(top, bitmap=bitmap)
|
||||
bm.pack(side=LEFT, padx='3m', pady='3m')
|
||||
|
||||
# 3. Create a row of buttons at the bottom of the dialog.
|
||||
|
||||
var = IntVar()
|
||||
buttons = []
|
||||
i = 0
|
||||
for but in args:
|
||||
b = Button(bot, text=but, command=lambda v=var,i=i: v.set(i))
|
||||
buttons.append(b)
|
||||
if i == default:
|
||||
bd = Frame(bot, relief=SUNKEN, borderwidth=1)
|
||||
bd.pack(side=LEFT, expand=1, padx='3m', pady='2m')
|
||||
b.lift()
|
||||
b.pack (in_=bd, side=LEFT,
|
||||
padx='2m', pady='2m', ipadx='2m', ipady='1m')
|
||||
else:
|
||||
b.pack (side=LEFT, expand=1,
|
||||
padx='3m', pady='3m', ipadx='2m', ipady='1m')
|
||||
i = i+1
|
||||
|
||||
# 4. Set up a binding for <Return>, if there's a default,
|
||||
# set a grab, and claim the focus too.
|
||||
|
||||
if default >= 0:
|
||||
w.bind('<Return>',
|
||||
lambda e, b=buttons[default], v=var, i=default:
|
||||
(b.flash(),
|
||||
v.set(i)))
|
||||
|
||||
oldFocus = w.focus_get()
|
||||
w.grab_set()
|
||||
w.focus_set()
|
||||
|
||||
# 5. Wait for the user to respond, then restore the focus
|
||||
# and return the index of the selected button.
|
||||
|
||||
w.waitvar(var)
|
||||
w.destroy()
|
||||
if oldFocus: oldFocus.focus_set()
|
||||
return var.get()
|
||||
|
||||
# The rest is the test program.
|
||||
|
||||
def go():
|
||||
i = dialog(mainWidget,
|
||||
'Not Responding',
|
||||
"The file server isn't responding right now; "
|
||||
"I'll keep trying.",
|
||||
'',
|
||||
-1,
|
||||
'OK')
|
||||
print 'pressed button', i
|
||||
i = dialog(mainWidget,
|
||||
'File Modified',
|
||||
'File "tcl.h" has been modified since '
|
||||
'the last time it was saved. '
|
||||
'Do you want to save it before exiting the application?',
|
||||
'warning',
|
||||
0,
|
||||
'Save File',
|
||||
'Discard Changes',
|
||||
'Return To Editor')
|
||||
print 'pressed button', i
|
||||
|
||||
def test():
|
||||
import sys
|
||||
global mainWidget
|
||||
mainWidget = Frame()
|
||||
Pack.config(mainWidget)
|
||||
start = Button(mainWidget, text='Press Here To Start', command=go)
|
||||
start.pack()
|
||||
endit = Button(mainWidget, text="Exit", command=sys.exit)
|
||||
endit.pack(fill=BOTH)
|
||||
mainWidget.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
91
Demo/tkinter/guido/electrons.py
Executable file
91
Demo/tkinter/guido/electrons.py
Executable file
@@ -0,0 +1,91 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# Simulate "electrons" migrating across the screen.
|
||||
# An optional bitmap file in can be in the background.
|
||||
#
|
||||
# Usage: electrons [n [bitmapfile]]
|
||||
#
|
||||
# n is the number of electrons to animate; default is 30.
|
||||
#
|
||||
# The bitmap file can be any X11 bitmap file (look in
|
||||
# /usr/include/X11/bitmaps for samples); it is displayed as the
|
||||
# background of the animation. Default is no bitmap.
|
||||
|
||||
from Tkinter import *
|
||||
import random
|
||||
|
||||
|
||||
# The graphical interface
|
||||
class Electrons:
|
||||
|
||||
# Create our objects
|
||||
def __init__(self, n, bitmap = None):
|
||||
self.n = n
|
||||
self.tk = tk = Tk()
|
||||
self.canvas = c = Canvas(tk)
|
||||
c.pack()
|
||||
width, height = tk.getint(c['width']), tk.getint(c['height'])
|
||||
|
||||
# Add background bitmap
|
||||
if bitmap:
|
||||
self.bitmap = c.create_bitmap(width/2, height/2,
|
||||
bitmap=bitmap,
|
||||
foreground='blue')
|
||||
|
||||
self.pieces = []
|
||||
x1, y1, x2, y2 = 10,70,14,74
|
||||
for i in range(n):
|
||||
p = c.create_oval(x1, y1, x2, y2, fill='red')
|
||||
self.pieces.append(p)
|
||||
y1, y2 = y1 +2, y2 + 2
|
||||
self.tk.update()
|
||||
|
||||
def random_move(self, n):
|
||||
c = self.canvas
|
||||
for p in self.pieces:
|
||||
x = random.choice(range(-2,4))
|
||||
y = random.choice(range(-3,4))
|
||||
c.move(p, x, y)
|
||||
self.tk.update()
|
||||
|
||||
# Run -- allow 500 movemens
|
||||
def run(self):
|
||||
try:
|
||||
for i in range(500):
|
||||
self.random_move(self.n)
|
||||
except TclError:
|
||||
try:
|
||||
self.tk.destroy()
|
||||
except TclError:
|
||||
pass
|
||||
|
||||
|
||||
# Main program
|
||||
def main():
|
||||
import sys, string
|
||||
|
||||
# First argument is number of electrons, default 30
|
||||
if sys.argv[1:]:
|
||||
n = string.atoi(sys.argv[1])
|
||||
else:
|
||||
n = 30
|
||||
|
||||
# Second argument is bitmap file, default none
|
||||
if sys.argv[2:]:
|
||||
bitmap = sys.argv[2]
|
||||
# Reverse meaning of leading '@' compared to Tk
|
||||
if bitmap[0] == '@': bitmap = bitmap[1:]
|
||||
else: bitmap = '@' + bitmap
|
||||
else:
|
||||
bitmap = None
|
||||
|
||||
# Create the graphical objects...
|
||||
h = Electrons(n, bitmap)
|
||||
|
||||
# ...and run!
|
||||
h.run()
|
||||
|
||||
|
||||
# Call main when run as script
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
154
Demo/tkinter/guido/hanoi.py
Normal file
154
Demo/tkinter/guido/hanoi.py
Normal file
@@ -0,0 +1,154 @@
|
||||
# Animated Towers of Hanoi using Tk with optional bitmap file in
|
||||
# background.
|
||||
#
|
||||
# Usage: tkhanoi [n [bitmapfile]]
|
||||
#
|
||||
# n is the number of pieces to animate; default is 4, maximum 15.
|
||||
#
|
||||
# The bitmap file can be any X11 bitmap file (look in
|
||||
# /usr/include/X11/bitmaps for samples); it is displayed as the
|
||||
# background of the animation. Default is no bitmap.
|
||||
|
||||
# This uses Steen Lumholt's Tk interface
|
||||
from Tkinter import *
|
||||
|
||||
|
||||
# Basic Towers-of-Hanoi algorithm: move n pieces from a to b, using c
|
||||
# as temporary. For each move, call report()
|
||||
def hanoi(n, a, b, c, report):
|
||||
if n <= 0: return
|
||||
hanoi(n-1, a, c, b, report)
|
||||
report(n, a, b)
|
||||
hanoi(n-1, c, b, a, report)
|
||||
|
||||
|
||||
# The graphical interface
|
||||
class Tkhanoi:
|
||||
|
||||
# Create our objects
|
||||
def __init__(self, n, bitmap = None):
|
||||
self.n = n
|
||||
self.tk = tk = Tk()
|
||||
self.canvas = c = Canvas(tk)
|
||||
c.pack()
|
||||
width, height = tk.getint(c['width']), tk.getint(c['height'])
|
||||
|
||||
# Add background bitmap
|
||||
if bitmap:
|
||||
self.bitmap = c.create_bitmap(width//2, height//2,
|
||||
bitmap=bitmap,
|
||||
foreground='blue')
|
||||
|
||||
# Generate pegs
|
||||
pegwidth = 10
|
||||
pegheight = height//2
|
||||
pegdist = width//3
|
||||
x1, y1 = (pegdist-pegwidth)//2, height*1//3
|
||||
x2, y2 = x1+pegwidth, y1+pegheight
|
||||
self.pegs = []
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
|
||||
self.pegs.append(p)
|
||||
x1, x2 = x1+pegdist, x2+pegdist
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
|
||||
self.pegs.append(p)
|
||||
x1, x2 = x1+pegdist, x2+pegdist
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='black')
|
||||
self.pegs.append(p)
|
||||
self.tk.update()
|
||||
|
||||
# Generate pieces
|
||||
pieceheight = pegheight//16
|
||||
maxpiecewidth = pegdist*2//3
|
||||
minpiecewidth = 2*pegwidth
|
||||
self.pegstate = [[], [], []]
|
||||
self.pieces = {}
|
||||
x1, y1 = (pegdist-maxpiecewidth)//2, y2-pieceheight-2
|
||||
x2, y2 = x1+maxpiecewidth, y1+pieceheight
|
||||
dx = (maxpiecewidth-minpiecewidth) // (2*max(1, n-1))
|
||||
for i in range(n, 0, -1):
|
||||
p = c.create_rectangle(x1, y1, x2, y2, fill='red')
|
||||
self.pieces[i] = p
|
||||
self.pegstate[0].append(i)
|
||||
x1, x2 = x1 + dx, x2-dx
|
||||
y1, y2 = y1 - pieceheight-2, y2-pieceheight-2
|
||||
self.tk.update()
|
||||
self.tk.after(25)
|
||||
|
||||
# Run -- never returns
|
||||
def run(self):
|
||||
while 1:
|
||||
hanoi(self.n, 0, 1, 2, self.report)
|
||||
hanoi(self.n, 1, 2, 0, self.report)
|
||||
hanoi(self.n, 2, 0, 1, self.report)
|
||||
hanoi(self.n, 0, 2, 1, self.report)
|
||||
hanoi(self.n, 2, 1, 0, self.report)
|
||||
hanoi(self.n, 1, 0, 2, self.report)
|
||||
|
||||
# Reporting callback for the actual hanoi function
|
||||
def report(self, i, a, b):
|
||||
if self.pegstate[a][-1] != i: raise RuntimeError # Assertion
|
||||
del self.pegstate[a][-1]
|
||||
p = self.pieces[i]
|
||||
c = self.canvas
|
||||
|
||||
# Lift the piece above peg a
|
||||
ax1, ay1, ax2, ay2 = c.bbox(self.pegs[a])
|
||||
while 1:
|
||||
x1, y1, x2, y2 = c.bbox(p)
|
||||
if y2 < ay1: break
|
||||
c.move(p, 0, -1)
|
||||
self.tk.update()
|
||||
|
||||
# Move it towards peg b
|
||||
bx1, by1, bx2, by2 = c.bbox(self.pegs[b])
|
||||
newcenter = (bx1+bx2)//2
|
||||
while 1:
|
||||
x1, y1, x2, y2 = c.bbox(p)
|
||||
center = (x1+x2)//2
|
||||
if center == newcenter: break
|
||||
if center > newcenter: c.move(p, -1, 0)
|
||||
else: c.move(p, 1, 0)
|
||||
self.tk.update()
|
||||
|
||||
# Move it down on top of the previous piece
|
||||
pieceheight = y2-y1
|
||||
newbottom = by2 - pieceheight*len(self.pegstate[b]) - 2
|
||||
while 1:
|
||||
x1, y1, x2, y2 = c.bbox(p)
|
||||
if y2 >= newbottom: break
|
||||
c.move(p, 0, 1)
|
||||
self.tk.update()
|
||||
|
||||
# Update peg state
|
||||
self.pegstate[b].append(i)
|
||||
|
||||
|
||||
# Main program
|
||||
def main():
|
||||
import sys, string
|
||||
|
||||
# First argument is number of pegs, default 4
|
||||
if sys.argv[1:]:
|
||||
n = string.atoi(sys.argv[1])
|
||||
else:
|
||||
n = 4
|
||||
|
||||
# Second argument is bitmap file, default none
|
||||
if sys.argv[2:]:
|
||||
bitmap = sys.argv[2]
|
||||
# Reverse meaning of leading '@' compared to Tk
|
||||
if bitmap[0] == '@': bitmap = bitmap[1:]
|
||||
else: bitmap = '@' + bitmap
|
||||
else:
|
||||
bitmap = None
|
||||
|
||||
# Create the graphical objects...
|
||||
h = Tkhanoi(n, bitmap)
|
||||
|
||||
# ...and run!
|
||||
h.run()
|
||||
|
||||
|
||||
# Call main when run as script
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
17
Demo/tkinter/guido/hello.py
Normal file
17
Demo/tkinter/guido/hello.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Display hello, world in a button; clicking it quits the program
|
||||
|
||||
import sys
|
||||
from Tkinter import *
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
button = Button(root)
|
||||
button['text'] = 'Hello, world'
|
||||
button['command'] = quit_callback # See below
|
||||
button.pack()
|
||||
root.mainloop()
|
||||
|
||||
def quit_callback():
|
||||
sys.exit(0)
|
||||
|
||||
main()
|
||||
23
Demo/tkinter/guido/imagedraw.py
Normal file
23
Demo/tkinter/guido/imagedraw.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""Draw on top of an image"""
|
||||
|
||||
from Tkinter import *
|
||||
import sys
|
||||
|
||||
def main():
|
||||
filename = sys.argv[1]
|
||||
root = Tk()
|
||||
img = PhotoImage(file=filename)
|
||||
w, h = img.width(), img.height()
|
||||
canv = Canvas(root, width=w, height=h)
|
||||
canv.create_image(0, 0, anchor=NW, image=img)
|
||||
canv.pack()
|
||||
canv.bind('<Button-1>', blob)
|
||||
root.mainloop()
|
||||
|
||||
def blob(event):
|
||||
x, y = event.x, event.y
|
||||
canv = event.widget
|
||||
r = 5
|
||||
canv.create_oval(x-r, y-r, x+r, y+r, fill='red', outline="")
|
||||
|
||||
main()
|
||||
12
Demo/tkinter/guido/imageview.py
Normal file
12
Demo/tkinter/guido/imageview.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from Tkinter import *
|
||||
import sys
|
||||
|
||||
def main():
|
||||
filename = sys.argv[1]
|
||||
root = Tk()
|
||||
img = PhotoImage(file=filename)
|
||||
label = Label(root, image=img)
|
||||
label.pack()
|
||||
root.mainloop()
|
||||
|
||||
main()
|
||||
98
Demo/tkinter/guido/kill.py
Executable file
98
Demo/tkinter/guido/kill.py
Executable file
@@ -0,0 +1,98 @@
|
||||
#! /usr/bin/env python
|
||||
# Tkinter interface to Linux `kill' command.
|
||||
|
||||
from Tkinter import *
|
||||
from string import splitfields
|
||||
from string import split
|
||||
import commands
|
||||
import os
|
||||
|
||||
class BarButton(Menubutton):
|
||||
def __init__(self, master=None, **cnf):
|
||||
apply(Menubutton.__init__, (self, master), cnf)
|
||||
self.pack(side=LEFT)
|
||||
self.menu = Menu(self, name='menu')
|
||||
self['menu'] = self.menu
|
||||
|
||||
class Kill(Frame):
|
||||
# List of (name, option, pid_column)
|
||||
format_list = [('Default', '', 0),
|
||||
('Long', '-l', 2),
|
||||
('User', '-u', 1),
|
||||
('Jobs', '-j', 1),
|
||||
('Signal', '-s', 1),
|
||||
('Memory', '-m', 0),
|
||||
('VM', '-v', 0),
|
||||
('Hex', '-X', 0)]
|
||||
def kill(self, selected):
|
||||
c = self.format_list[self.format.get()][2]
|
||||
pid = split(selected)[c]
|
||||
os.system('kill -9 ' + pid)
|
||||
self.do_update()
|
||||
def do_update(self):
|
||||
name, option, column = self.format_list[self.format.get()]
|
||||
s = commands.getoutput('ps -w ' + option)
|
||||
list = splitfields(s, '\n')
|
||||
self.header.set(list[0])
|
||||
del list[0]
|
||||
y = self.frame.vscroll.get()[0]
|
||||
self.frame.list.delete(0, AtEnd())
|
||||
for line in list:
|
||||
self.frame.list.insert(0, line)
|
||||
self.frame.list.yview(int(y))
|
||||
def do_motion(self, e):
|
||||
e.widget.select_clear(0, END)
|
||||
e.widget.select_set(e.widget.nearest(e.y))
|
||||
def do_leave(self, e):
|
||||
e.widget.select_clear(0, END)
|
||||
def do_1(self, e):
|
||||
self.kill(e.widget.get(e.widget.nearest(e.y)))
|
||||
def __init__(self, master=None, **cnf):
|
||||
Frame.__init__(self, master, cnf)
|
||||
self.pack(expand=1, fill=BOTH)
|
||||
self.bar = Frame(self, name='bar', relief=RAISED,
|
||||
borderwidth=2)
|
||||
self.bar.pack(fill=X)
|
||||
self.bar.file = BarButton(self.bar, text='File')
|
||||
self.bar.file.menu.add_command(
|
||||
label='Quit', command=self.quit)
|
||||
self.bar.view = BarButton(self.bar, text='View')
|
||||
self.format = IntVar(self)
|
||||
self.format.set(2)
|
||||
for num in range(len(self.format_list)):
|
||||
self.bar.view.menu.add_radiobutton(
|
||||
label=self.format_list[num][0],
|
||||
command=self.do_update,
|
||||
variable=self.format,
|
||||
value=num)
|
||||
#self.bar.view.menu.add_separator()
|
||||
#XXX ...
|
||||
self.bar.tk_menuBar(self.bar.file, self.bar.view)
|
||||
self.frame = Frame(self, relief=RAISED, borderwidth=2)
|
||||
self.frame.pack(expand=1, fill=BOTH)
|
||||
self.header = StringVar(self)
|
||||
self.frame.label = Label(self.frame, relief=FLAT, anchor=NW,
|
||||
borderwidth=0,
|
||||
textvariable=self.header)
|
||||
self.frame.label.pack(fill=X)
|
||||
self.frame.vscroll = Scrollbar(self.frame, orient=VERTICAL)
|
||||
self.frame.list = Listbox(self.frame, relief=SUNKEN,
|
||||
selectbackground='#eed5b7',
|
||||
selectborderwidth=0,
|
||||
yscroll=self.frame.vscroll.set)
|
||||
self.frame.vscroll['command'] = self.frame.list.yview
|
||||
self.frame.vscroll.pack(side=RIGHT, fill=Y)
|
||||
self.frame.list.pack(expand=1, fill=BOTH)
|
||||
self.update = Button(self, text="Update",
|
||||
command=self.do_update)
|
||||
self.update.pack(expand=1, fill=X)
|
||||
self.frame.list.bind('<Motion>', self.do_motion)
|
||||
self.frame.list.bind('<Leave>', self.do_leave)
|
||||
self.frame.list.bind('<1>', self.do_1)
|
||||
self.do_update()
|
||||
|
||||
if __name__ == '__main__':
|
||||
kill = Kill(None, borderwidth=5)
|
||||
kill.winfo_toplevel().title('Tkinter Process Killer')
|
||||
kill.winfo_toplevel().minsize(1, 1)
|
||||
kill.mainloop()
|
||||
37
Demo/tkinter/guido/listtree.py
Normal file
37
Demo/tkinter/guido/listtree.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# List a remote app's widget tree (names and classes only)
|
||||
|
||||
import sys
|
||||
import string
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
def listtree(master, app):
|
||||
list = Listbox(master, name='list')
|
||||
list.pack(expand=1, fill=BOTH)
|
||||
listnodes(list, app, '.', 0)
|
||||
return list
|
||||
|
||||
def listnodes(list, app, widget, level):
|
||||
klass = list.send(app, 'winfo', 'class', widget)
|
||||
## i = string.rindex(widget, '.')
|
||||
## list.insert(END, '%s%s (%s)' % ((level-1)*'. ', widget[i:], klass))
|
||||
list.insert(END, '%s (%s)' % (widget, klass))
|
||||
children = list.tk.splitlist(
|
||||
list.send(app, 'winfo', 'children', widget))
|
||||
for c in children:
|
||||
listnodes(list, app, c, level+1)
|
||||
|
||||
def main():
|
||||
if not sys.argv[1:]:
|
||||
sys.stderr.write('Usage: listtree appname\n')
|
||||
sys.exit(2)
|
||||
app = sys.argv[1]
|
||||
tk = Tk()
|
||||
tk.minsize(1, 1)
|
||||
f = Frame(tk, name='f')
|
||||
f.pack(expand=1, fill=BOTH)
|
||||
list = listtree(f, app)
|
||||
tk.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
285
Demo/tkinter/guido/mbox.py
Executable file
285
Demo/tkinter/guido/mbox.py
Executable file
@@ -0,0 +1,285 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# Scan MH folder, display results in window
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import getopt
|
||||
import string
|
||||
import mhlib
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
from dialog import dialog
|
||||
|
||||
mailbox = os.environ['HOME'] + '/Mail'
|
||||
|
||||
def main():
|
||||
global root, tk, top, mid, bot
|
||||
global folderbox, foldermenu, scanbox, scanmenu, viewer
|
||||
global folder, seq
|
||||
global mh, mhf
|
||||
|
||||
# Parse command line options
|
||||
|
||||
folder = 'inbox'
|
||||
seq = 'all'
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], '')
|
||||
except getopt.error, msg:
|
||||
print msg
|
||||
sys.exit(2)
|
||||
for arg in args:
|
||||
if arg[:1] == '+':
|
||||
folder = arg[1:]
|
||||
else:
|
||||
seq = arg
|
||||
|
||||
# Initialize MH
|
||||
|
||||
mh = mhlib.MH()
|
||||
mhf = mh.openfolder(folder)
|
||||
|
||||
# Build widget hierarchy
|
||||
|
||||
root = Tk()
|
||||
tk = root.tk
|
||||
|
||||
top = Frame(root)
|
||||
top.pack({'expand': 1, 'fill': 'both'})
|
||||
|
||||
# Build right part: folder list
|
||||
|
||||
right = Frame(top)
|
||||
right.pack({'fill': 'y', 'side': 'right'})
|
||||
|
||||
folderbar = Scrollbar(right, {'relief': 'sunken', 'bd': 2})
|
||||
folderbar.pack({'fill': 'y', 'side': 'right'})
|
||||
|
||||
folderbox = Listbox(right, {'exportselection': 0})
|
||||
folderbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
|
||||
|
||||
foldermenu = Menu(root)
|
||||
foldermenu.add('command',
|
||||
{'label': 'Open Folder',
|
||||
'command': open_folder})
|
||||
foldermenu.add('separator')
|
||||
foldermenu.add('command',
|
||||
{'label': 'Quit',
|
||||
'command': 'exit'})
|
||||
foldermenu.bind('<ButtonRelease-3>', folder_unpost)
|
||||
|
||||
folderbox['yscrollcommand'] = (folderbar, 'set')
|
||||
folderbar['command'] = (folderbox, 'yview')
|
||||
folderbox.bind('<Double-1>', open_folder, 1)
|
||||
folderbox.bind('<3>', folder_post)
|
||||
|
||||
# Build left part: scan list
|
||||
|
||||
left = Frame(top)
|
||||
left.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
|
||||
|
||||
scanbar = Scrollbar(left, {'relief': 'sunken', 'bd': 2})
|
||||
scanbar.pack({'fill': 'y', 'side': 'right'})
|
||||
|
||||
scanbox = Listbox(left, {'font': 'fixed'})
|
||||
scanbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
|
||||
|
||||
scanmenu = Menu(root)
|
||||
scanmenu.add('command',
|
||||
{'label': 'Open Message',
|
||||
'command': open_message})
|
||||
scanmenu.add('command',
|
||||
{'label': 'Remove Message',
|
||||
'command': remove_message})
|
||||
scanmenu.add('command',
|
||||
{'label': 'Refile Message',
|
||||
'command': refile_message})
|
||||
scanmenu.add('separator')
|
||||
scanmenu.add('command',
|
||||
{'label': 'Quit',
|
||||
'command': 'exit'})
|
||||
scanmenu.bind('<ButtonRelease-3>', scan_unpost)
|
||||
|
||||
scanbox['yscrollcommand'] = (scanbar, 'set')
|
||||
scanbar['command'] = (scanbox, 'yview')
|
||||
scanbox.bind('<Double-1>', open_message)
|
||||
scanbox.bind('<3>', scan_post)
|
||||
|
||||
# Separator between middle and bottom part
|
||||
|
||||
rule2 = Frame(root, {'bg': 'black'})
|
||||
rule2.pack({'fill': 'x'})
|
||||
|
||||
# Build bottom part: current message
|
||||
|
||||
bot = Frame(root)
|
||||
bot.pack({'expand': 1, 'fill': 'both'})
|
||||
#
|
||||
viewer = None
|
||||
|
||||
# Window manager commands
|
||||
|
||||
root.minsize(800, 1) # Make window resizable
|
||||
|
||||
# Fill folderbox with text
|
||||
|
||||
setfolders()
|
||||
|
||||
# Fill scanbox with text
|
||||
|
||||
rescan()
|
||||
|
||||
# Enter mainloop
|
||||
|
||||
root.mainloop()
|
||||
|
||||
def folder_post(e):
|
||||
x, y = e.x_root, e.y_root
|
||||
foldermenu.post(x - 10, y - 10)
|
||||
foldermenu.grab_set()
|
||||
|
||||
def folder_unpost(e):
|
||||
tk.call('update', 'idletasks')
|
||||
foldermenu.grab_release()
|
||||
foldermenu.unpost()
|
||||
foldermenu.invoke('active')
|
||||
|
||||
def scan_post(e):
|
||||
x, y = e.x_root, e.y_root
|
||||
scanmenu.post(x - 10, y - 10)
|
||||
scanmenu.grab_set()
|
||||
|
||||
def scan_unpost(e):
|
||||
tk.call('update', 'idletasks')
|
||||
scanmenu.grab_release()
|
||||
scanmenu.unpost()
|
||||
scanmenu.invoke('active')
|
||||
|
||||
scanparser = re.compile('^ *([0-9]+)')
|
||||
|
||||
def open_folder(e=None):
|
||||
global folder, mhf
|
||||
sel = folderbox.curselection()
|
||||
if len(sel) != 1:
|
||||
if len(sel) > 1:
|
||||
msg = "Please open one folder at a time"
|
||||
else:
|
||||
msg = "Please select a folder to open"
|
||||
dialog(root, "Can't Open Folder", msg, "", 0, "OK")
|
||||
return
|
||||
i = sel[0]
|
||||
folder = folderbox.get(i)
|
||||
mhf = mh.openfolder(folder)
|
||||
rescan()
|
||||
|
||||
def open_message(e=None):
|
||||
global viewer
|
||||
sel = scanbox.curselection()
|
||||
if len(sel) != 1:
|
||||
if len(sel) > 1:
|
||||
msg = "Please open one message at a time"
|
||||
else:
|
||||
msg = "Please select a message to open"
|
||||
dialog(root, "Can't Open Message", msg, "", 0, "OK")
|
||||
return
|
||||
cursor = scanbox['cursor']
|
||||
scanbox['cursor'] = 'watch'
|
||||
tk.call('update', 'idletasks')
|
||||
i = sel[0]
|
||||
line = scanbox.get(i)
|
||||
if scanparser.match(line) >= 0:
|
||||
num = string.atoi(scanparser.group(1))
|
||||
m = mhf.openmessage(num)
|
||||
if viewer: viewer.destroy()
|
||||
from MimeViewer import MimeViewer
|
||||
viewer = MimeViewer(bot, '+%s/%d' % (folder, num), m)
|
||||
viewer.pack()
|
||||
viewer.show()
|
||||
scanbox['cursor'] = cursor
|
||||
|
||||
def interestingheader(header):
|
||||
return header != 'received'
|
||||
|
||||
def remove_message(e=None):
|
||||
itop = scanbox.nearest(0)
|
||||
sel = scanbox.curselection()
|
||||
if not sel:
|
||||
dialog(root, "No Message To Remove",
|
||||
"Please select a message to remove", "", 0, "OK")
|
||||
return
|
||||
todo = []
|
||||
for i in sel:
|
||||
line = scanbox.get(i)
|
||||
if scanparser.match(line) >= 0:
|
||||
todo.append(string.atoi(scanparser.group(1)))
|
||||
mhf.removemessages(todo)
|
||||
rescan()
|
||||
fixfocus(min(todo), itop)
|
||||
|
||||
lastrefile = ''
|
||||
tofolder = None
|
||||
def refile_message(e=None):
|
||||
global lastrefile, tofolder
|
||||
itop = scanbox.nearest(0)
|
||||
sel = scanbox.curselection()
|
||||
if not sel:
|
||||
dialog(root, "No Message To Refile",
|
||||
"Please select a message to refile", "", 0, "OK")
|
||||
return
|
||||
foldersel = folderbox.curselection()
|
||||
if len(foldersel) != 1:
|
||||
if not foldersel:
|
||||
msg = "Please select a folder to refile to"
|
||||
else:
|
||||
msg = "Please select exactly one folder to refile to"
|
||||
dialog(root, "No Folder To Refile", msg, "", 0, "OK")
|
||||
return
|
||||
refileto = folderbox.get(foldersel[0])
|
||||
todo = []
|
||||
for i in sel:
|
||||
line = scanbox.get(i)
|
||||
if scanparser.match(line) >= 0:
|
||||
todo.append(string.atoi(scanparser.group(1)))
|
||||
if lastrefile != refileto or not tofolder:
|
||||
lastrefile = refileto
|
||||
tofolder = None
|
||||
tofolder = mh.openfolder(lastrefile)
|
||||
mhf.refilemessages(todo, tofolder)
|
||||
rescan()
|
||||
fixfocus(min(todo), itop)
|
||||
|
||||
def fixfocus(near, itop):
|
||||
n = scanbox.size()
|
||||
for i in range(n):
|
||||
line = scanbox.get(repr(i))
|
||||
if scanparser.match(line) >= 0:
|
||||
num = string.atoi(scanparser.group(1))
|
||||
if num >= near:
|
||||
break
|
||||
else:
|
||||
i = 'end'
|
||||
scanbox.select_from(i)
|
||||
scanbox.yview(itop)
|
||||
|
||||
def setfolders():
|
||||
folderbox.delete(0, 'end')
|
||||
for fn in mh.listallfolders():
|
||||
folderbox.insert('end', fn)
|
||||
|
||||
def rescan():
|
||||
global viewer
|
||||
if viewer:
|
||||
viewer.destroy()
|
||||
viewer = None
|
||||
scanbox.delete(0, 'end')
|
||||
for line in scanfolder(folder, seq):
|
||||
scanbox.insert('end', line)
|
||||
|
||||
def scanfolder(folder = 'inbox', sequence = 'all'):
|
||||
return map(
|
||||
lambda line: line[:-1],
|
||||
os.popen('scan +%s %s' % (folder, sequence), 'r').readlines())
|
||||
|
||||
main()
|
||||
47
Demo/tkinter/guido/newmenubardemo.py
Executable file
47
Demo/tkinter/guido/newmenubardemo.py
Executable file
@@ -0,0 +1,47 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Play with the new Tk 8.0 toplevel menu option."""
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
class App:
|
||||
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
|
||||
self.menubar = Menu(self.master)
|
||||
|
||||
self.filemenu = Menu(self.menubar)
|
||||
|
||||
self.filemenu.add_command(label="New")
|
||||
self.filemenu.add_command(label="Open...")
|
||||
self.filemenu.add_command(label="Close")
|
||||
self.filemenu.add_separator()
|
||||
self.filemenu.add_command(label="Quit", command=self.master.quit)
|
||||
|
||||
self.editmenu = Menu(self.menubar)
|
||||
|
||||
self.editmenu.add_command(label="Cut")
|
||||
self.editmenu.add_command(label="Copy")
|
||||
self.editmenu.add_command(label="Paste")
|
||||
|
||||
self.helpmenu = Menu(self.menubar, name='help')
|
||||
|
||||
self.helpmenu.add_command(label="About...")
|
||||
|
||||
self.menubar.add_cascade(label="File", menu=self.filemenu)
|
||||
self.menubar.add_cascade(label="Edit", menu=self.editmenu)
|
||||
self.menubar.add_cascade(label="Help", menu=self.helpmenu)
|
||||
|
||||
self.top = Toplevel(menu=self.menubar)
|
||||
|
||||
# Rest of app goes here...
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
root.withdraw()
|
||||
app = App(root)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
27
Demo/tkinter/guido/optionmenu.py
Normal file
27
Demo/tkinter/guido/optionmenu.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# option menu sample (Fredrik Lundh, September 1997)
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
root = Tk()
|
||||
|
||||
#
|
||||
# standard usage
|
||||
|
||||
var1 = StringVar()
|
||||
var1.set("One") # default selection
|
||||
|
||||
menu1 = OptionMenu(root, var1, "One", "Two", "Three")
|
||||
menu1.pack()
|
||||
|
||||
#
|
||||
# initialize from a sequence
|
||||
|
||||
CHOICES = "Aah", "Bee", "Cee", "Dee", "Eff"
|
||||
|
||||
var2 = StringVar()
|
||||
var2.set(CHOICES[0])
|
||||
|
||||
menu2 = apply(OptionMenu, (root, var2) + tuple(CHOICES))
|
||||
menu2.pack()
|
||||
|
||||
root.mainloop()
|
||||
60
Demo/tkinter/guido/paint.py
Normal file
60
Demo/tkinter/guido/paint.py
Normal file
@@ -0,0 +1,60 @@
|
||||
""""Paint program by Dave Michell.
|
||||
|
||||
Subject: tkinter "paint" example
|
||||
From: Dave Mitchell <davem@magnet.com>
|
||||
To: python-list@cwi.nl
|
||||
Date: Fri, 23 Jan 1998 12:18:05 -0500 (EST)
|
||||
|
||||
Not too long ago (last week maybe?) someone posted a request
|
||||
for an example of a paint program using Tkinter. Try as I might
|
||||
I can't seem to find it in the archive, so i'll just post mine
|
||||
here and hope that the person who requested it sees this!
|
||||
|
||||
All this does is put up a canvas and draw a smooth black line
|
||||
whenever you have the mouse button down, but hopefully it will
|
||||
be enough to start with.. It would be easy enough to add some
|
||||
options like other shapes or colors...
|
||||
|
||||
yours,
|
||||
dave mitchell
|
||||
davem@magnet.com
|
||||
"""
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
"""paint.py: not exactly a paint program.. just a smooth line drawing demo."""
|
||||
|
||||
b1 = "up"
|
||||
xold, yold = None, None
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
drawing_area = Canvas(root)
|
||||
drawing_area.pack()
|
||||
drawing_area.bind("<Motion>", motion)
|
||||
drawing_area.bind("<ButtonPress-1>", b1down)
|
||||
drawing_area.bind("<ButtonRelease-1>", b1up)
|
||||
root.mainloop()
|
||||
|
||||
def b1down(event):
|
||||
global b1
|
||||
b1 = "down" # you only want to draw when the button is down
|
||||
# because "Motion" events happen -all the time-
|
||||
|
||||
def b1up(event):
|
||||
global b1, xold, yold
|
||||
b1 = "up"
|
||||
xold = None # reset the line when you let go of the button
|
||||
yold = None
|
||||
|
||||
def motion(event):
|
||||
if b1 == "down":
|
||||
global xold, yold
|
||||
if xold is not None and yold is not None:
|
||||
event.widget.create_line(xold,yold,event.x,event.y,smooth=TRUE)
|
||||
# here's where you draw it. smooth. neat.
|
||||
xold = event.x
|
||||
yold = event.y
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
159
Demo/tkinter/guido/rmt.py
Executable file
159
Demo/tkinter/guido/rmt.py
Executable file
@@ -0,0 +1,159 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# A Python program implementing rmt, an application for remotely
|
||||
# controlling other Tk applications.
|
||||
# Cf. Ousterhout, Tcl and the Tk Toolkit, Figs. 27.5-8, pp. 273-276.
|
||||
|
||||
# Note that because of forward references in the original, we
|
||||
# sometimes delay bindings until after the corresponding procedure is
|
||||
# defined. We also introduce names for some unnamed code blocks in
|
||||
# the original because of restrictions on lambda forms in Python.
|
||||
|
||||
# XXX This should be written in a more Python-like style!!!
|
||||
|
||||
from Tkinter import *
|
||||
import sys
|
||||
|
||||
# 1. Create basic application structure: menu bar on top of
|
||||
# text widget, scrollbar on right.
|
||||
|
||||
root = Tk()
|
||||
tk = root.tk
|
||||
mBar = Frame(root, relief=RAISED, borderwidth=2)
|
||||
mBar.pack(fill=X)
|
||||
|
||||
f = Frame(root)
|
||||
f.pack(expand=1, fill=BOTH)
|
||||
s = Scrollbar(f, relief=FLAT)
|
||||
s.pack(side=RIGHT, fill=Y)
|
||||
t = Text(f, relief=RAISED, borderwidth=2, yscrollcommand=s.set, setgrid=1)
|
||||
t.pack(side=LEFT, fill=BOTH, expand=1)
|
||||
t.tag_config('bold', font='-Adobe-Courier-Bold-R-Normal-*-120-*')
|
||||
s['command'] = t.yview
|
||||
|
||||
root.title('Tk Remote Controller')
|
||||
root.iconname('Tk Remote')
|
||||
|
||||
# 2. Create menu button and menus.
|
||||
|
||||
file = Menubutton(mBar, text='File', underline=0)
|
||||
file.pack(side=LEFT)
|
||||
file_m = Menu(file)
|
||||
file['menu'] = file_m
|
||||
file_m_apps = Menu(file_m, tearoff=0)
|
||||
file_m.add_cascade(label='Select Application', underline=0,
|
||||
menu=file_m_apps)
|
||||
file_m.add_command(label='Quit', underline=0, command=sys.exit)
|
||||
|
||||
# 3. Create bindings for text widget to allow commands to be
|
||||
# entered and information to be selected. New characters
|
||||
# can only be added at the end of the text (can't ever move
|
||||
# insertion point).
|
||||
|
||||
def single1(e):
|
||||
x = e.x
|
||||
y = e.y
|
||||
t.setvar('tk_priv(selectMode)', 'char')
|
||||
t.mark_set('anchor', At(x, y))
|
||||
# Should focus W
|
||||
t.bind('<1>', single1)
|
||||
|
||||
def double1(e):
|
||||
x = e.x
|
||||
y = e.y
|
||||
t.setvar('tk_priv(selectMode)', 'word')
|
||||
t.tk_textSelectTo(At(x, y))
|
||||
t.bind('<Double-1>', double1)
|
||||
|
||||
def triple1(e):
|
||||
x = e.x
|
||||
y = e.y
|
||||
t.setvar('tk_priv(selectMode)', 'line')
|
||||
t.tk_textSelectTo(At(x, y))
|
||||
t.bind('<Triple-1>', triple1)
|
||||
|
||||
def returnkey(e):
|
||||
t.insert(AtInsert(), '\n')
|
||||
invoke()
|
||||
t.bind('<Return>', returnkey)
|
||||
|
||||
def controlv(e):
|
||||
t.insert(AtInsert(), t.selection_get())
|
||||
t.yview_pickplace(AtInsert())
|
||||
if t.index(AtInsert())[-2:] == '.0':
|
||||
invoke()
|
||||
t.bind('<Control-v>', controlv)
|
||||
|
||||
# 4. Procedure to backspace over one character, as long as
|
||||
# the character isn't part of the prompt.
|
||||
|
||||
def backspace(e):
|
||||
if t.index('promptEnd') != t.index('insert - 1 char'):
|
||||
t.delete('insert - 1 char', AtInsert())
|
||||
t.yview_pickplace(AtInsert())
|
||||
t.bind('<BackSpace>', backspace)
|
||||
t.bind('<Control-h>', backspace)
|
||||
t.bind('<Delete>', backspace)
|
||||
|
||||
|
||||
# 5. Procedure that's invoked when return is typed: if
|
||||
# there's not yet a complete command (e.g. braces are open)
|
||||
# then do nothing. Otherwise, execute command (locally or
|
||||
# remotely), output the result or error message, and issue
|
||||
# a new prompt.
|
||||
|
||||
def invoke():
|
||||
cmd = t.get('promptEnd + 1 char', AtInsert())
|
||||
if t.getboolean(tk.call('info', 'complete', cmd)): # XXX
|
||||
if app == root.winfo_name():
|
||||
msg = tk.call('eval', cmd) # XXX
|
||||
else:
|
||||
msg = t.send(app, cmd)
|
||||
if msg:
|
||||
t.insert(AtInsert(), msg + '\n')
|
||||
prompt()
|
||||
t.yview_pickplace(AtInsert())
|
||||
|
||||
def prompt():
|
||||
t.insert(AtInsert(), app + ': ')
|
||||
t.mark_set('promptEnd', 'insert - 1 char')
|
||||
t.tag_add('bold', 'insert linestart', 'promptEnd')
|
||||
|
||||
# 6. Procedure to select a new application. Also changes
|
||||
# the prompt on the current command line to reflect the new
|
||||
# name.
|
||||
|
||||
def newApp(appName):
|
||||
global app
|
||||
app = appName
|
||||
t.delete('promptEnd linestart', 'promptEnd')
|
||||
t.insert('promptEnd', appName + ':')
|
||||
t.tag_add('bold', 'promptEnd linestart', 'promptEnd')
|
||||
|
||||
def fillAppsMenu():
|
||||
file_m_apps.add('command')
|
||||
file_m_apps.delete(0, 'last')
|
||||
names = root.winfo_interps()
|
||||
names = list(names)
|
||||
names.sort()
|
||||
for name in names:
|
||||
try:
|
||||
root.send(name, 'winfo name .')
|
||||
except TclError:
|
||||
# Inoperative window -- ignore it
|
||||
pass
|
||||
else:
|
||||
file_m_apps.add_command(
|
||||
label=name,
|
||||
command=lambda name=name: newApp(name))
|
||||
|
||||
file_m_apps['postcommand'] = fillAppsMenu
|
||||
mBar.tk_menuBar(file)
|
||||
|
||||
# 7. Miscellaneous initialization.
|
||||
|
||||
app = root.winfo_name()
|
||||
prompt()
|
||||
t.focus()
|
||||
|
||||
root.mainloop()
|
||||
637
Demo/tkinter/guido/solitaire.py
Executable file
637
Demo/tkinter/guido/solitaire.py
Executable file
@@ -0,0 +1,637 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Solitaire game, much like the one that comes with MS Windows.
|
||||
|
||||
Limitations:
|
||||
|
||||
- No cute graphical images for the playing cards faces or backs.
|
||||
- No scoring or timer.
|
||||
- No undo.
|
||||
- No option to turn 3 cards at a time.
|
||||
- No keyboard shortcuts.
|
||||
- Less fancy animation when you win.
|
||||
- The determination of which stack you drag to is more relaxed.
|
||||
|
||||
Apology:
|
||||
|
||||
I'm not much of a card player, so my terminology in these comments may
|
||||
at times be a little unusual. If you have suggestions, please let me
|
||||
know!
|
||||
|
||||
"""
|
||||
|
||||
# Imports
|
||||
|
||||
import math
|
||||
import random
|
||||
|
||||
from Tkinter import *
|
||||
from Canvas import Rectangle, CanvasText, Group, Window
|
||||
|
||||
|
||||
# Fix a bug in Canvas.Group as distributed in Python 1.4. The
|
||||
# distributed bind() method is broken. Rather than asking you to fix
|
||||
# the source, we fix it here by deriving a subclass:
|
||||
|
||||
class Group(Group):
|
||||
def bind(self, sequence=None, command=None):
|
||||
return self.canvas.tag_bind(self.id, sequence, command)
|
||||
|
||||
|
||||
# Constants determining the size and lay-out of cards and stacks. We
|
||||
# work in a "grid" where each card/stack is surrounded by MARGIN
|
||||
# pixels of space on each side, so adjacent stacks are separated by
|
||||
# 2*MARGIN pixels. OFFSET is the offset used for displaying the
|
||||
# face down cards in the row stacks.
|
||||
|
||||
CARDWIDTH = 100
|
||||
CARDHEIGHT = 150
|
||||
MARGIN = 10
|
||||
XSPACING = CARDWIDTH + 2*MARGIN
|
||||
YSPACING = CARDHEIGHT + 4*MARGIN
|
||||
OFFSET = 5
|
||||
|
||||
# The background color, green to look like a playing table. The
|
||||
# standard green is way too bright, and dark green is way to dark, so
|
||||
# we use something in between. (There are a few more colors that
|
||||
# could be customized, but they are less controversial.)
|
||||
|
||||
BACKGROUND = '#070'
|
||||
|
||||
|
||||
# Suits and colors. The values of the symbolic suit names are the
|
||||
# strings used to display them (you change these and VALNAMES to
|
||||
# internationalize the game). The COLOR dictionary maps suit names to
|
||||
# colors (red and black) which must be Tk color names. The keys() of
|
||||
# the COLOR dictionary conveniently provides us with a list of all
|
||||
# suits (in arbitrary order).
|
||||
|
||||
HEARTS = 'Heart'
|
||||
DIAMONDS = 'Diamond'
|
||||
CLUBS = 'Club'
|
||||
SPADES = 'Spade'
|
||||
|
||||
RED = 'red'
|
||||
BLACK = 'black'
|
||||
|
||||
COLOR = {}
|
||||
for s in (HEARTS, DIAMONDS):
|
||||
COLOR[s] = RED
|
||||
for s in (CLUBS, SPADES):
|
||||
COLOR[s] = BLACK
|
||||
|
||||
ALLSUITS = COLOR.keys()
|
||||
NSUITS = len(ALLSUITS)
|
||||
|
||||
|
||||
# Card values are 1-13. We also define symbolic names for the picture
|
||||
# cards. ALLVALUES is a list of all card values.
|
||||
|
||||
ACE = 1
|
||||
JACK = 11
|
||||
QUEEN = 12
|
||||
KING = 13
|
||||
ALLVALUES = range(1, 14) # (one more than the highest value)
|
||||
NVALUES = len(ALLVALUES)
|
||||
|
||||
|
||||
# VALNAMES is a list that maps a card value to string. It contains a
|
||||
# dummy element at index 0 so it can be indexed directly with the card
|
||||
# value.
|
||||
|
||||
VALNAMES = ["", "A"] + map(str, range(2, 11)) + ["J", "Q", "K"]
|
||||
|
||||
|
||||
# Solitaire constants. The only one I can think of is the number of
|
||||
# row stacks.
|
||||
|
||||
NROWS = 7
|
||||
|
||||
|
||||
# The rest of the program consists of class definitions. These are
|
||||
# further described in their documentation strings.
|
||||
|
||||
|
||||
class Card:
|
||||
|
||||
"""A playing card.
|
||||
|
||||
A card doesn't record to which stack it belongs; only the stack
|
||||
records this (it turns out that we always know this from the
|
||||
context, and this saves a ``double update'' with potential for
|
||||
inconsistencies).
|
||||
|
||||
Public methods:
|
||||
|
||||
moveto(x, y) -- move the card to an absolute position
|
||||
moveby(dx, dy) -- move the card by a relative offset
|
||||
tkraise() -- raise the card to the top of its stack
|
||||
showface(), showback() -- turn the card face up or down & raise it
|
||||
|
||||
Public read-only instance variables:
|
||||
|
||||
suit, value, color -- the card's suit, value and color
|
||||
face_shown -- true when the card is shown face up, else false
|
||||
|
||||
Semi-public read-only instance variables (XXX should be made
|
||||
private):
|
||||
|
||||
group -- the Canvas.Group representing the card
|
||||
x, y -- the position of the card's top left corner
|
||||
|
||||
Private instance variables:
|
||||
|
||||
__back, __rect, __text -- the canvas items making up the card
|
||||
|
||||
(To show the card face up, the text item is placed in front of
|
||||
rect and the back is placed behind it. To show it face down, this
|
||||
is reversed. The card is created face down.)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, suit, value, canvas):
|
||||
"""Card constructor.
|
||||
|
||||
Arguments are the card's suit and value, and the canvas widget.
|
||||
|
||||
The card is created at position (0, 0), with its face down
|
||||
(adding it to a stack will position it according to that
|
||||
stack's rules).
|
||||
|
||||
"""
|
||||
self.suit = suit
|
||||
self.value = value
|
||||
self.color = COLOR[suit]
|
||||
self.face_shown = 0
|
||||
|
||||
self.x = self.y = 0
|
||||
self.group = Group(canvas)
|
||||
|
||||
text = "%s %s" % (VALNAMES[value], suit)
|
||||
self.__text = CanvasText(canvas, CARDWIDTH//2, 0,
|
||||
anchor=N, fill=self.color, text=text)
|
||||
self.group.addtag_withtag(self.__text)
|
||||
|
||||
self.__rect = Rectangle(canvas, 0, 0, CARDWIDTH, CARDHEIGHT,
|
||||
outline='black', fill='white')
|
||||
self.group.addtag_withtag(self.__rect)
|
||||
|
||||
self.__back = Rectangle(canvas, MARGIN, MARGIN,
|
||||
CARDWIDTH-MARGIN, CARDHEIGHT-MARGIN,
|
||||
outline='black', fill='blue')
|
||||
self.group.addtag_withtag(self.__back)
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a string for debug print statements."""
|
||||
return "Card(%r, %r)" % (self.suit, self.value)
|
||||
|
||||
def moveto(self, x, y):
|
||||
"""Move the card to absolute position (x, y)."""
|
||||
self.moveby(x - self.x, y - self.y)
|
||||
|
||||
def moveby(self, dx, dy):
|
||||
"""Move the card by (dx, dy)."""
|
||||
self.x = self.x + dx
|
||||
self.y = self.y + dy
|
||||
self.group.move(dx, dy)
|
||||
|
||||
def tkraise(self):
|
||||
"""Raise the card above all other objects in its canvas."""
|
||||
self.group.tkraise()
|
||||
|
||||
def showface(self):
|
||||
"""Turn the card's face up."""
|
||||
self.tkraise()
|
||||
self.__rect.tkraise()
|
||||
self.__text.tkraise()
|
||||
self.face_shown = 1
|
||||
|
||||
def showback(self):
|
||||
"""Turn the card's face down."""
|
||||
self.tkraise()
|
||||
self.__rect.tkraise()
|
||||
self.__back.tkraise()
|
||||
self.face_shown = 0
|
||||
|
||||
|
||||
class Stack:
|
||||
|
||||
"""A generic stack of cards.
|
||||
|
||||
This is used as a base class for all other stacks (e.g. the deck,
|
||||
the suit stacks, and the row stacks).
|
||||
|
||||
Public methods:
|
||||
|
||||
add(card) -- add a card to the stack
|
||||
delete(card) -- delete a card from the stack
|
||||
showtop() -- show the top card (if any) face up
|
||||
deal() -- delete and return the top card, or None if empty
|
||||
|
||||
Method that subclasses may override:
|
||||
|
||||
position(card) -- move the card to its proper (x, y) position
|
||||
|
||||
The default position() method places all cards at the stack's
|
||||
own (x, y) position.
|
||||
|
||||
userclickhandler(), userdoubleclickhandler() -- called to do
|
||||
subclass specific things on single and double clicks
|
||||
|
||||
The default user (single) click handler shows the top card
|
||||
face up. The default user double click handler calls the user
|
||||
single click handler.
|
||||
|
||||
usermovehandler(cards) -- called to complete a subpile move
|
||||
|
||||
The default user move handler moves all moved cards back to
|
||||
their original position (by calling the position() method).
|
||||
|
||||
Private methods:
|
||||
|
||||
clickhandler(event), doubleclickhandler(event),
|
||||
motionhandler(event), releasehandler(event) -- event handlers
|
||||
|
||||
The default event handlers turn the top card of the stack with
|
||||
its face up on a (single or double) click, and also support
|
||||
moving a subpile around.
|
||||
|
||||
startmoving(event) -- begin a move operation
|
||||
finishmoving() -- finish a move operation
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, x, y, game=None):
|
||||
"""Stack constructor.
|
||||
|
||||
Arguments are the stack's nominal x and y position (the top
|
||||
left corner of the first card placed in the stack), and the
|
||||
game object (which is used to get the canvas; subclasses use
|
||||
the game object to find other stacks).
|
||||
|
||||
"""
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.game = game
|
||||
self.cards = []
|
||||
self.group = Group(self.game.canvas)
|
||||
self.group.bind('<1>', self.clickhandler)
|
||||
self.group.bind('<Double-1>', self.doubleclickhandler)
|
||||
self.group.bind('<B1-Motion>', self.motionhandler)
|
||||
self.group.bind('<ButtonRelease-1>', self.releasehandler)
|
||||
self.makebottom()
|
||||
|
||||
def makebottom(self):
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
"""Return a string for debug print statements."""
|
||||
return "%s(%d, %d)" % (self.__class__.__name__, self.x, self.y)
|
||||
|
||||
# Public methods
|
||||
|
||||
def add(self, card):
|
||||
self.cards.append(card)
|
||||
card.tkraise()
|
||||
self.position(card)
|
||||
self.group.addtag_withtag(card.group)
|
||||
|
||||
def delete(self, card):
|
||||
self.cards.remove(card)
|
||||
card.group.dtag(self.group)
|
||||
|
||||
def showtop(self):
|
||||
if self.cards:
|
||||
self.cards[-1].showface()
|
||||
|
||||
def deal(self):
|
||||
if not self.cards:
|
||||
return None
|
||||
card = self.cards[-1]
|
||||
self.delete(card)
|
||||
return card
|
||||
|
||||
# Subclass overridable methods
|
||||
|
||||
def position(self, card):
|
||||
card.moveto(self.x, self.y)
|
||||
|
||||
def userclickhandler(self):
|
||||
self.showtop()
|
||||
|
||||
def userdoubleclickhandler(self):
|
||||
self.userclickhandler()
|
||||
|
||||
def usermovehandler(self, cards):
|
||||
for card in cards:
|
||||
self.position(card)
|
||||
|
||||
# Event handlers
|
||||
|
||||
def clickhandler(self, event):
|
||||
self.finishmoving() # In case we lost an event
|
||||
self.userclickhandler()
|
||||
self.startmoving(event)
|
||||
|
||||
def motionhandler(self, event):
|
||||
self.keepmoving(event)
|
||||
|
||||
def releasehandler(self, event):
|
||||
self.keepmoving(event)
|
||||
self.finishmoving()
|
||||
|
||||
def doubleclickhandler(self, event):
|
||||
self.finishmoving() # In case we lost an event
|
||||
self.userdoubleclickhandler()
|
||||
self.startmoving(event)
|
||||
|
||||
# Move internals
|
||||
|
||||
moving = None
|
||||
|
||||
def startmoving(self, event):
|
||||
self.moving = None
|
||||
tags = self.game.canvas.gettags('current')
|
||||
for i in range(len(self.cards)):
|
||||
card = self.cards[i]
|
||||
if card.group.tag in tags:
|
||||
break
|
||||
else:
|
||||
return
|
||||
if not card.face_shown:
|
||||
return
|
||||
self.moving = self.cards[i:]
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
for card in self.moving:
|
||||
card.tkraise()
|
||||
|
||||
def keepmoving(self, event):
|
||||
if not self.moving:
|
||||
return
|
||||
dx = event.x - self.lastx
|
||||
dy = event.y - self.lasty
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
if dx or dy:
|
||||
for card in self.moving:
|
||||
card.moveby(dx, dy)
|
||||
|
||||
def finishmoving(self):
|
||||
cards = self.moving
|
||||
self.moving = None
|
||||
if cards:
|
||||
self.usermovehandler(cards)
|
||||
|
||||
|
||||
class Deck(Stack):
|
||||
|
||||
"""The deck is a stack with support for shuffling.
|
||||
|
||||
New methods:
|
||||
|
||||
fill() -- create the playing cards
|
||||
shuffle() -- shuffle the playing cards
|
||||
|
||||
A single click moves the top card to the game's open deck and
|
||||
moves it face up; if we're out of cards, it moves the open deck
|
||||
back to the deck.
|
||||
|
||||
"""
|
||||
|
||||
def makebottom(self):
|
||||
bottom = Rectangle(self.game.canvas,
|
||||
self.x, self.y,
|
||||
self.x+CARDWIDTH, self.y+CARDHEIGHT,
|
||||
outline='black', fill=BACKGROUND)
|
||||
self.group.addtag_withtag(bottom)
|
||||
|
||||
def fill(self):
|
||||
for suit in ALLSUITS:
|
||||
for value in ALLVALUES:
|
||||
self.add(Card(suit, value, self.game.canvas))
|
||||
|
||||
def shuffle(self):
|
||||
n = len(self.cards)
|
||||
newcards = []
|
||||
for i in randperm(n):
|
||||
newcards.append(self.cards[i])
|
||||
self.cards = newcards
|
||||
|
||||
def userclickhandler(self):
|
||||
opendeck = self.game.opendeck
|
||||
card = self.deal()
|
||||
if not card:
|
||||
while 1:
|
||||
card = opendeck.deal()
|
||||
if not card:
|
||||
break
|
||||
self.add(card)
|
||||
card.showback()
|
||||
else:
|
||||
self.game.opendeck.add(card)
|
||||
card.showface()
|
||||
|
||||
|
||||
def randperm(n):
|
||||
"""Function returning a random permutation of range(n)."""
|
||||
r = range(n)
|
||||
x = []
|
||||
while r:
|
||||
i = random.choice(r)
|
||||
x.append(i)
|
||||
r.remove(i)
|
||||
return x
|
||||
|
||||
|
||||
class OpenStack(Stack):
|
||||
|
||||
def acceptable(self, cards):
|
||||
return 0
|
||||
|
||||
def usermovehandler(self, cards):
|
||||
card = cards[0]
|
||||
stack = self.game.closeststack(card)
|
||||
if not stack or stack is self or not stack.acceptable(cards):
|
||||
Stack.usermovehandler(self, cards)
|
||||
else:
|
||||
for card in cards:
|
||||
self.delete(card)
|
||||
stack.add(card)
|
||||
self.game.wincheck()
|
||||
|
||||
def userdoubleclickhandler(self):
|
||||
if not self.cards:
|
||||
return
|
||||
card = self.cards[-1]
|
||||
if not card.face_shown:
|
||||
self.userclickhandler()
|
||||
return
|
||||
for s in self.game.suits:
|
||||
if s.acceptable([card]):
|
||||
self.delete(card)
|
||||
s.add(card)
|
||||
self.game.wincheck()
|
||||
break
|
||||
|
||||
|
||||
class SuitStack(OpenStack):
|
||||
|
||||
def makebottom(self):
|
||||
bottom = Rectangle(self.game.canvas,
|
||||
self.x, self.y,
|
||||
self.x+CARDWIDTH, self.y+CARDHEIGHT,
|
||||
outline='black', fill='')
|
||||
|
||||
def userclickhandler(self):
|
||||
pass
|
||||
|
||||
def userdoubleclickhandler(self):
|
||||
pass
|
||||
|
||||
def acceptable(self, cards):
|
||||
if len(cards) != 1:
|
||||
return 0
|
||||
card = cards[0]
|
||||
if not self.cards:
|
||||
return card.value == ACE
|
||||
topcard = self.cards[-1]
|
||||
return card.suit == topcard.suit and card.value == topcard.value + 1
|
||||
|
||||
|
||||
class RowStack(OpenStack):
|
||||
|
||||
def acceptable(self, cards):
|
||||
card = cards[0]
|
||||
if not self.cards:
|
||||
return card.value == KING
|
||||
topcard = self.cards[-1]
|
||||
if not topcard.face_shown:
|
||||
return 0
|
||||
return card.color != topcard.color and card.value == topcard.value - 1
|
||||
|
||||
def position(self, card):
|
||||
y = self.y
|
||||
for c in self.cards:
|
||||
if c == card:
|
||||
break
|
||||
if c.face_shown:
|
||||
y = y + 2*MARGIN
|
||||
else:
|
||||
y = y + OFFSET
|
||||
card.moveto(self.x, y)
|
||||
|
||||
|
||||
class Solitaire:
|
||||
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
|
||||
self.canvas = Canvas(self.master,
|
||||
background=BACKGROUND,
|
||||
highlightthickness=0,
|
||||
width=NROWS*XSPACING,
|
||||
height=3*YSPACING + 20 + MARGIN)
|
||||
self.canvas.pack(fill=BOTH, expand=TRUE)
|
||||
|
||||
self.dealbutton = Button(self.canvas,
|
||||
text="Deal",
|
||||
highlightthickness=0,
|
||||
background=BACKGROUND,
|
||||
activebackground="green",
|
||||
command=self.deal)
|
||||
Window(self.canvas, MARGIN, 3*YSPACING + 20,
|
||||
window=self.dealbutton, anchor=SW)
|
||||
|
||||
x = MARGIN
|
||||
y = MARGIN
|
||||
|
||||
self.deck = Deck(x, y, self)
|
||||
|
||||
x = x + XSPACING
|
||||
self.opendeck = OpenStack(x, y, self)
|
||||
|
||||
x = x + XSPACING
|
||||
self.suits = []
|
||||
for i in range(NSUITS):
|
||||
x = x + XSPACING
|
||||
self.suits.append(SuitStack(x, y, self))
|
||||
|
||||
x = MARGIN
|
||||
y = y + YSPACING
|
||||
|
||||
self.rows = []
|
||||
for i in range(NROWS):
|
||||
self.rows.append(RowStack(x, y, self))
|
||||
x = x + XSPACING
|
||||
|
||||
self.openstacks = [self.opendeck] + self.suits + self.rows
|
||||
|
||||
self.deck.fill()
|
||||
self.deal()
|
||||
|
||||
def wincheck(self):
|
||||
for s in self.suits:
|
||||
if len(s.cards) != NVALUES:
|
||||
return
|
||||
self.win()
|
||||
self.deal()
|
||||
|
||||
def win(self):
|
||||
"""Stupid animation when you win."""
|
||||
cards = []
|
||||
for s in self.openstacks:
|
||||
cards = cards + s.cards
|
||||
while cards:
|
||||
card = random.choice(cards)
|
||||
cards.remove(card)
|
||||
self.animatedmoveto(card, self.deck)
|
||||
|
||||
def animatedmoveto(self, card, dest):
|
||||
for i in range(10, 0, -1):
|
||||
dx, dy = (dest.x-card.x)//i, (dest.y-card.y)//i
|
||||
card.moveby(dx, dy)
|
||||
self.master.update_idletasks()
|
||||
|
||||
def closeststack(self, card):
|
||||
closest = None
|
||||
cdist = 999999999
|
||||
# Since we only compare distances,
|
||||
# we don't bother to take the square root.
|
||||
for stack in self.openstacks:
|
||||
dist = (stack.x - card.x)**2 + (stack.y - card.y)**2
|
||||
if dist < cdist:
|
||||
closest = stack
|
||||
cdist = dist
|
||||
return closest
|
||||
|
||||
def deal(self):
|
||||
self.reset()
|
||||
self.deck.shuffle()
|
||||
for i in range(NROWS):
|
||||
for r in self.rows[i:]:
|
||||
card = self.deck.deal()
|
||||
r.add(card)
|
||||
for r in self.rows:
|
||||
r.showtop()
|
||||
|
||||
def reset(self):
|
||||
for stack in self.openstacks:
|
||||
while 1:
|
||||
card = stack.deal()
|
||||
if not card:
|
||||
break
|
||||
self.deck.add(card)
|
||||
card.showback()
|
||||
|
||||
|
||||
# Main function, run when invoked as a stand-alone Python program.
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
game = Solitaire(root)
|
||||
root.protocol('WM_DELETE_WINDOW', root.quit)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
634
Demo/tkinter/guido/sortvisu.py
Executable file
634
Demo/tkinter/guido/sortvisu.py
Executable file
@@ -0,0 +1,634 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""Sorting algorithms visualizer using Tkinter.
|
||||
|
||||
This module is comprised of three ``components'':
|
||||
|
||||
- an array visualizer with methods that implement basic sorting
|
||||
operations (compare, swap) as well as methods for ``annotating'' the
|
||||
sorting algorithm (e.g. to show the pivot element);
|
||||
|
||||
- a number of sorting algorithms (currently quicksort, insertion sort,
|
||||
selection sort and bubble sort, as well as a randomization function),
|
||||
all using the array visualizer for its basic operations and with calls
|
||||
to its annotation methods;
|
||||
|
||||
- and a ``driver'' class which can be used as a Grail applet or as a
|
||||
stand-alone application.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from Tkinter import *
|
||||
from Canvas import Line, Rectangle
|
||||
import random
|
||||
|
||||
|
||||
XGRID = 10
|
||||
YGRID = 10
|
||||
WIDTH = 6
|
||||
|
||||
|
||||
class Array:
|
||||
|
||||
def __init__(self, master, data=None):
|
||||
self.master = master
|
||||
self.frame = Frame(self.master)
|
||||
self.frame.pack(fill=X)
|
||||
self.label = Label(self.frame)
|
||||
self.label.pack()
|
||||
self.canvas = Canvas(self.frame)
|
||||
self.canvas.pack()
|
||||
self.report = Label(self.frame)
|
||||
self.report.pack()
|
||||
self.left = Line(self.canvas, 0, 0, 0, 0)
|
||||
self.right = Line(self.canvas, 0, 0, 0, 0)
|
||||
self.pivot = Line(self.canvas, 0, 0, 0, 0)
|
||||
self.items = []
|
||||
self.size = self.maxvalue = 0
|
||||
if data:
|
||||
self.setdata(data)
|
||||
|
||||
def setdata(self, data):
|
||||
olditems = self.items
|
||||
self.items = []
|
||||
for item in olditems:
|
||||
item.delete()
|
||||
self.size = len(data)
|
||||
self.maxvalue = max(data)
|
||||
self.canvas.config(width=(self.size+1)*XGRID,
|
||||
height=(self.maxvalue+1)*YGRID)
|
||||
for i in range(self.size):
|
||||
self.items.append(ArrayItem(self, i, data[i]))
|
||||
self.reset("Sort demo, size %d" % self.size)
|
||||
|
||||
speed = "normal"
|
||||
|
||||
def setspeed(self, speed):
|
||||
self.speed = speed
|
||||
|
||||
def destroy(self):
|
||||
self.frame.destroy()
|
||||
|
||||
in_mainloop = 0
|
||||
stop_mainloop = 0
|
||||
|
||||
def cancel(self):
|
||||
self.stop_mainloop = 1
|
||||
if self.in_mainloop:
|
||||
self.master.quit()
|
||||
|
||||
def step(self):
|
||||
if self.in_mainloop:
|
||||
self.master.quit()
|
||||
|
||||
Cancelled = "Array.Cancelled" # Exception
|
||||
|
||||
def wait(self, msecs):
|
||||
if self.speed == "fastest":
|
||||
msecs = 0
|
||||
elif self.speed == "fast":
|
||||
msecs = msecs//10
|
||||
elif self.speed == "single-step":
|
||||
msecs = 1000000000
|
||||
if not self.stop_mainloop:
|
||||
self.master.update()
|
||||
id = self.master.after(msecs, self.master.quit)
|
||||
self.in_mainloop = 1
|
||||
self.master.mainloop()
|
||||
self.master.after_cancel(id)
|
||||
self.in_mainloop = 0
|
||||
if self.stop_mainloop:
|
||||
self.stop_mainloop = 0
|
||||
self.message("Cancelled")
|
||||
raise Array.Cancelled
|
||||
|
||||
def getsize(self):
|
||||
return self.size
|
||||
|
||||
def show_partition(self, first, last):
|
||||
for i in range(self.size):
|
||||
item = self.items[i]
|
||||
if first <= i < last:
|
||||
item.item.config(fill='red')
|
||||
else:
|
||||
item.item.config(fill='orange')
|
||||
self.hide_left_right_pivot()
|
||||
|
||||
def hide_partition(self):
|
||||
for i in range(self.size):
|
||||
item = self.items[i]
|
||||
item.item.config(fill='red')
|
||||
self.hide_left_right_pivot()
|
||||
|
||||
def show_left(self, left):
|
||||
if not 0 <= left < self.size:
|
||||
self.hide_left()
|
||||
return
|
||||
x1, y1, x2, y2 = self.items[left].position()
|
||||
## top, bot = HIRO
|
||||
self.left.coords([(x1-2, 0), (x1-2, 9999)])
|
||||
self.master.update()
|
||||
|
||||
def show_right(self, right):
|
||||
if not 0 <= right < self.size:
|
||||
self.hide_right()
|
||||
return
|
||||
x1, y1, x2, y2 = self.items[right].position()
|
||||
self.right.coords(((x2+2, 0), (x2+2, 9999)))
|
||||
self.master.update()
|
||||
|
||||
def hide_left_right_pivot(self):
|
||||
self.hide_left()
|
||||
self.hide_right()
|
||||
self.hide_pivot()
|
||||
|
||||
def hide_left(self):
|
||||
self.left.coords(((0, 0), (0, 0)))
|
||||
|
||||
def hide_right(self):
|
||||
self.right.coords(((0, 0), (0, 0)))
|
||||
|
||||
def show_pivot(self, pivot):
|
||||
x1, y1, x2, y2 = self.items[pivot].position()
|
||||
self.pivot.coords(((0, y1-2), (9999, y1-2)))
|
||||
|
||||
def hide_pivot(self):
|
||||
self.pivot.coords(((0, 0), (0, 0)))
|
||||
|
||||
def swap(self, i, j):
|
||||
if i == j: return
|
||||
self.countswap()
|
||||
item = self.items[i]
|
||||
other = self.items[j]
|
||||
self.items[i], self.items[j] = other, item
|
||||
item.swapwith(other)
|
||||
|
||||
def compare(self, i, j):
|
||||
self.countcompare()
|
||||
item = self.items[i]
|
||||
other = self.items[j]
|
||||
return item.compareto(other)
|
||||
|
||||
def reset(self, msg):
|
||||
self.ncompares = 0
|
||||
self.nswaps = 0
|
||||
self.message(msg)
|
||||
self.updatereport()
|
||||
self.hide_partition()
|
||||
|
||||
def message(self, msg):
|
||||
self.label.config(text=msg)
|
||||
|
||||
def countswap(self):
|
||||
self.nswaps = self.nswaps + 1
|
||||
self.updatereport()
|
||||
|
||||
def countcompare(self):
|
||||
self.ncompares = self.ncompares + 1
|
||||
self.updatereport()
|
||||
|
||||
def updatereport(self):
|
||||
text = "%d cmps, %d swaps" % (self.ncompares, self.nswaps)
|
||||
self.report.config(text=text)
|
||||
|
||||
|
||||
class ArrayItem:
|
||||
|
||||
def __init__(self, array, index, value):
|
||||
self.array = array
|
||||
self.index = index
|
||||
self.value = value
|
||||
x1, y1, x2, y2 = self.position()
|
||||
self.item = Rectangle(array.canvas, x1, y1, x2, y2,
|
||||
fill='red', outline='black', width=1)
|
||||
self.item.bind('<Button-1>', self.mouse_down)
|
||||
self.item.bind('<Button1-Motion>', self.mouse_move)
|
||||
self.item.bind('<ButtonRelease-1>', self.mouse_up)
|
||||
|
||||
def delete(self):
|
||||
item = self.item
|
||||
self.array = None
|
||||
self.item = None
|
||||
item.delete()
|
||||
|
||||
def mouse_down(self, event):
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
self.origx = event.x
|
||||
self.origy = event.y
|
||||
self.item.tkraise()
|
||||
|
||||
def mouse_move(self, event):
|
||||
self.item.move(event.x - self.lastx, event.y - self.lasty)
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
def mouse_up(self, event):
|
||||
i = self.nearestindex(event.x)
|
||||
if i >= self.array.getsize():
|
||||
i = self.array.getsize() - 1
|
||||
if i < 0:
|
||||
i = 0
|
||||
other = self.array.items[i]
|
||||
here = self.index
|
||||
self.array.items[here], self.array.items[i] = other, self
|
||||
self.index = i
|
||||
x1, y1, x2, y2 = self.position()
|
||||
self.item.coords(((x1, y1), (x2, y2)))
|
||||
other.setindex(here)
|
||||
|
||||
def setindex(self, index):
|
||||
nsteps = steps(self.index, index)
|
||||
if not nsteps: return
|
||||
if self.array.speed == "fastest":
|
||||
nsteps = 0
|
||||
oldpts = self.position()
|
||||
self.index = index
|
||||
newpts = self.position()
|
||||
trajectory = interpolate(oldpts, newpts, nsteps)
|
||||
self.item.tkraise()
|
||||
for pts in trajectory:
|
||||
self.item.coords((pts[:2], pts[2:]))
|
||||
self.array.wait(50)
|
||||
|
||||
def swapwith(self, other):
|
||||
nsteps = steps(self.index, other.index)
|
||||
if not nsteps: return
|
||||
if self.array.speed == "fastest":
|
||||
nsteps = 0
|
||||
myoldpts = self.position()
|
||||
otheroldpts = other.position()
|
||||
self.index, other.index = other.index, self.index
|
||||
mynewpts = self.position()
|
||||
othernewpts = other.position()
|
||||
myfill = self.item['fill']
|
||||
otherfill = other.item['fill']
|
||||
self.item.config(fill='green')
|
||||
other.item.config(fill='yellow')
|
||||
self.array.master.update()
|
||||
if self.array.speed == "single-step":
|
||||
self.item.coords((mynewpts[:2], mynewpts[2:]))
|
||||
other.item.coords((othernewpts[:2], othernewpts[2:]))
|
||||
self.array.master.update()
|
||||
self.item.config(fill=myfill)
|
||||
other.item.config(fill=otherfill)
|
||||
self.array.wait(0)
|
||||
return
|
||||
mytrajectory = interpolate(myoldpts, mynewpts, nsteps)
|
||||
othertrajectory = interpolate(otheroldpts, othernewpts, nsteps)
|
||||
if self.value > other.value:
|
||||
self.item.tkraise()
|
||||
other.item.tkraise()
|
||||
else:
|
||||
other.item.tkraise()
|
||||
self.item.tkraise()
|
||||
try:
|
||||
for i in range(len(mytrajectory)):
|
||||
mypts = mytrajectory[i]
|
||||
otherpts = othertrajectory[i]
|
||||
self.item.coords((mypts[:2], mypts[2:]))
|
||||
other.item.coords((otherpts[:2], otherpts[2:]))
|
||||
self.array.wait(50)
|
||||
finally:
|
||||
mypts = mytrajectory[-1]
|
||||
otherpts = othertrajectory[-1]
|
||||
self.item.coords((mypts[:2], mypts[2:]))
|
||||
other.item.coords((otherpts[:2], otherpts[2:]))
|
||||
self.item.config(fill=myfill)
|
||||
other.item.config(fill=otherfill)
|
||||
|
||||
def compareto(self, other):
|
||||
myfill = self.item['fill']
|
||||
otherfill = other.item['fill']
|
||||
outcome = cmp(self.value, other.value)
|
||||
if outcome < 0:
|
||||
myflash = 'white'
|
||||
otherflash = 'black'
|
||||
elif outcome > 0:
|
||||
myflash = 'black'
|
||||
otherflash = 'white'
|
||||
else:
|
||||
myflash = otherflash = 'grey'
|
||||
try:
|
||||
self.item.config(fill=myflash)
|
||||
other.item.config(fill=otherflash)
|
||||
self.array.wait(500)
|
||||
finally:
|
||||
self.item.config(fill=myfill)
|
||||
other.item.config(fill=otherfill)
|
||||
return outcome
|
||||
|
||||
def position(self):
|
||||
x1 = (self.index+1)*XGRID - WIDTH//2
|
||||
x2 = x1+WIDTH
|
||||
y2 = (self.array.maxvalue+1)*YGRID
|
||||
y1 = y2 - (self.value)*YGRID
|
||||
return x1, y1, x2, y2
|
||||
|
||||
def nearestindex(self, x):
|
||||
return int(round(float(x)/XGRID)) - 1
|
||||
|
||||
|
||||
# Subroutines that don't need an object
|
||||
|
||||
def steps(here, there):
|
||||
nsteps = abs(here - there)
|
||||
if nsteps <= 3:
|
||||
nsteps = nsteps * 3
|
||||
elif nsteps <= 5:
|
||||
nsteps = nsteps * 2
|
||||
elif nsteps > 10:
|
||||
nsteps = 10
|
||||
return nsteps
|
||||
|
||||
def interpolate(oldpts, newpts, n):
|
||||
if len(oldpts) != len(newpts):
|
||||
raise ValueError, "can't interpolate arrays of different length"
|
||||
pts = [0]*len(oldpts)
|
||||
res = [tuple(oldpts)]
|
||||
for i in range(1, n):
|
||||
for k in range(len(pts)):
|
||||
pts[k] = oldpts[k] + (newpts[k] - oldpts[k])*i//n
|
||||
res.append(tuple(pts))
|
||||
res.append(tuple(newpts))
|
||||
return res
|
||||
|
||||
|
||||
# Various (un)sorting algorithms
|
||||
|
||||
def uniform(array):
|
||||
size = array.getsize()
|
||||
array.setdata([(size+1)//2] * size)
|
||||
array.reset("Uniform data, size %d" % size)
|
||||
|
||||
def distinct(array):
|
||||
size = array.getsize()
|
||||
array.setdata(range(1, size+1))
|
||||
array.reset("Distinct data, size %d" % size)
|
||||
|
||||
def randomize(array):
|
||||
array.reset("Randomizing")
|
||||
n = array.getsize()
|
||||
for i in range(n):
|
||||
j = random.randint(0, n-1)
|
||||
array.swap(i, j)
|
||||
array.message("Randomized")
|
||||
|
||||
def insertionsort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Insertion sort")
|
||||
for i in range(1, size):
|
||||
j = i-1
|
||||
while j >= 0:
|
||||
if array.compare(j, j+1) <= 0:
|
||||
break
|
||||
array.swap(j, j+1)
|
||||
j = j-1
|
||||
array.message("Sorted")
|
||||
|
||||
def selectionsort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Selection sort")
|
||||
try:
|
||||
for i in range(size):
|
||||
array.show_partition(i, size)
|
||||
for j in range(i+1, size):
|
||||
if array.compare(i, j) > 0:
|
||||
array.swap(i, j)
|
||||
array.message("Sorted")
|
||||
finally:
|
||||
array.hide_partition()
|
||||
|
||||
def bubblesort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Bubble sort")
|
||||
for i in range(size):
|
||||
for j in range(1, size):
|
||||
if array.compare(j-1, j) > 0:
|
||||
array.swap(j-1, j)
|
||||
array.message("Sorted")
|
||||
|
||||
def quicksort(array):
|
||||
size = array.getsize()
|
||||
array.reset("Quicksort")
|
||||
try:
|
||||
stack = [(0, size)]
|
||||
while stack:
|
||||
first, last = stack[-1]
|
||||
del stack[-1]
|
||||
array.show_partition(first, last)
|
||||
if last-first < 5:
|
||||
array.message("Insertion sort")
|
||||
for i in range(first+1, last):
|
||||
j = i-1
|
||||
while j >= first:
|
||||
if array.compare(j, j+1) <= 0:
|
||||
break
|
||||
array.swap(j, j+1)
|
||||
j = j-1
|
||||
continue
|
||||
array.message("Choosing pivot")
|
||||
j, i, k = first, (first+last)//2, last-1
|
||||
if array.compare(k, i) < 0:
|
||||
array.swap(k, i)
|
||||
if array.compare(k, j) < 0:
|
||||
array.swap(k, j)
|
||||
if array.compare(j, i) < 0:
|
||||
array.swap(j, i)
|
||||
pivot = j
|
||||
array.show_pivot(pivot)
|
||||
array.message("Pivot at left of partition")
|
||||
array.wait(1000)
|
||||
left = first
|
||||
right = last
|
||||
while 1:
|
||||
array.message("Sweep right pointer")
|
||||
right = right-1
|
||||
array.show_right(right)
|
||||
while right > first and array.compare(right, pivot) >= 0:
|
||||
right = right-1
|
||||
array.show_right(right)
|
||||
array.message("Sweep left pointer")
|
||||
left = left+1
|
||||
array.show_left(left)
|
||||
while left < last and array.compare(left, pivot) <= 0:
|
||||
left = left+1
|
||||
array.show_left(left)
|
||||
if left > right:
|
||||
array.message("End of partition")
|
||||
break
|
||||
array.message("Swap items")
|
||||
array.swap(left, right)
|
||||
array.message("Swap pivot back")
|
||||
array.swap(pivot, right)
|
||||
n1 = right-first
|
||||
n2 = last-left
|
||||
if n1 > 1: stack.append((first, right))
|
||||
if n2 > 1: stack.append((left, last))
|
||||
array.message("Sorted")
|
||||
finally:
|
||||
array.hide_partition()
|
||||
|
||||
def demosort(array):
|
||||
while 1:
|
||||
for alg in [quicksort, insertionsort, selectionsort, bubblesort]:
|
||||
randomize(array)
|
||||
alg(array)
|
||||
|
||||
|
||||
# Sort demo class -- usable as a Grail applet
|
||||
|
||||
class SortDemo:
|
||||
|
||||
def __init__(self, master, size=15):
|
||||
self.master = master
|
||||
self.size = size
|
||||
self.busy = 0
|
||||
self.array = Array(self.master)
|
||||
|
||||
self.botframe = Frame(master)
|
||||
self.botframe.pack(side=BOTTOM)
|
||||
self.botleftframe = Frame(self.botframe)
|
||||
self.botleftframe.pack(side=LEFT, fill=Y)
|
||||
self.botrightframe = Frame(self.botframe)
|
||||
self.botrightframe.pack(side=RIGHT, fill=Y)
|
||||
|
||||
self.b_qsort = Button(self.botleftframe,
|
||||
text="Quicksort", command=self.c_qsort)
|
||||
self.b_qsort.pack(fill=X)
|
||||
self.b_isort = Button(self.botleftframe,
|
||||
text="Insertion sort", command=self.c_isort)
|
||||
self.b_isort.pack(fill=X)
|
||||
self.b_ssort = Button(self.botleftframe,
|
||||
text="Selection sort", command=self.c_ssort)
|
||||
self.b_ssort.pack(fill=X)
|
||||
self.b_bsort = Button(self.botleftframe,
|
||||
text="Bubble sort", command=self.c_bsort)
|
||||
self.b_bsort.pack(fill=X)
|
||||
|
||||
# Terrible hack to overcome limitation of OptionMenu...
|
||||
class MyIntVar(IntVar):
|
||||
def __init__(self, master, demo):
|
||||
self.demo = demo
|
||||
IntVar.__init__(self, master)
|
||||
def set(self, value):
|
||||
IntVar.set(self, value)
|
||||
if str(value) != '0':
|
||||
self.demo.resize(value)
|
||||
|
||||
self.v_size = MyIntVar(self.master, self)
|
||||
self.v_size.set(size)
|
||||
sizes = [1, 2, 3, 4] + range(5, 55, 5)
|
||||
if self.size not in sizes:
|
||||
sizes.append(self.size)
|
||||
sizes.sort()
|
||||
self.m_size = apply(OptionMenu,
|
||||
(self.botleftframe, self.v_size) + tuple(sizes))
|
||||
self.m_size.pack(fill=X)
|
||||
|
||||
self.v_speed = StringVar(self.master)
|
||||
self.v_speed.set("normal")
|
||||
self.m_speed = OptionMenu(self.botleftframe, self.v_speed,
|
||||
"single-step", "normal", "fast", "fastest")
|
||||
self.m_speed.pack(fill=X)
|
||||
|
||||
self.b_step = Button(self.botleftframe,
|
||||
text="Step", command=self.c_step)
|
||||
self.b_step.pack(fill=X)
|
||||
|
||||
self.b_randomize = Button(self.botrightframe,
|
||||
text="Randomize", command=self.c_randomize)
|
||||
self.b_randomize.pack(fill=X)
|
||||
self.b_uniform = Button(self.botrightframe,
|
||||
text="Uniform", command=self.c_uniform)
|
||||
self.b_uniform.pack(fill=X)
|
||||
self.b_distinct = Button(self.botrightframe,
|
||||
text="Distinct", command=self.c_distinct)
|
||||
self.b_distinct.pack(fill=X)
|
||||
self.b_demo = Button(self.botrightframe,
|
||||
text="Demo", command=self.c_demo)
|
||||
self.b_demo.pack(fill=X)
|
||||
self.b_cancel = Button(self.botrightframe,
|
||||
text="Cancel", command=self.c_cancel)
|
||||
self.b_cancel.pack(fill=X)
|
||||
self.b_cancel.config(state=DISABLED)
|
||||
self.b_quit = Button(self.botrightframe,
|
||||
text="Quit", command=self.c_quit)
|
||||
self.b_quit.pack(fill=X)
|
||||
|
||||
def resize(self, newsize):
|
||||
if self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.size = newsize
|
||||
self.array.setdata(range(1, self.size+1))
|
||||
|
||||
def c_qsort(self):
|
||||
self.run(quicksort)
|
||||
|
||||
def c_isort(self):
|
||||
self.run(insertionsort)
|
||||
|
||||
def c_ssort(self):
|
||||
self.run(selectionsort)
|
||||
|
||||
def c_bsort(self):
|
||||
self.run(bubblesort)
|
||||
|
||||
def c_demo(self):
|
||||
self.run(demosort)
|
||||
|
||||
def c_randomize(self):
|
||||
self.run(randomize)
|
||||
|
||||
def c_uniform(self):
|
||||
self.run(uniform)
|
||||
|
||||
def c_distinct(self):
|
||||
self.run(distinct)
|
||||
|
||||
def run(self, func):
|
||||
if self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.busy = 1
|
||||
self.array.setspeed(self.v_speed.get())
|
||||
self.b_cancel.config(state=NORMAL)
|
||||
try:
|
||||
func(self.array)
|
||||
except Array.Cancelled:
|
||||
pass
|
||||
self.b_cancel.config(state=DISABLED)
|
||||
self.busy = 0
|
||||
|
||||
def c_cancel(self):
|
||||
if not self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.array.cancel()
|
||||
|
||||
def c_step(self):
|
||||
if not self.busy:
|
||||
self.master.bell()
|
||||
return
|
||||
self.v_speed.set("single-step")
|
||||
self.array.setspeed("single-step")
|
||||
self.array.step()
|
||||
|
||||
def c_quit(self):
|
||||
if self.busy:
|
||||
self.array.cancel()
|
||||
self.master.after_idle(self.master.quit)
|
||||
|
||||
|
||||
# Main program -- for stand-alone operation outside Grail
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
demo = SortDemo(root)
|
||||
root.protocol('WM_DELETE_WINDOW', demo.c_quit)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
845
Demo/tkinter/guido/ss1.py
Normal file
845
Demo/tkinter/guido/ss1.py
Normal file
@@ -0,0 +1,845 @@
|
||||
"""SS1 -- a spreadsheet."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import cgi
|
||||
import rexec
|
||||
from xml.parsers import expat
|
||||
|
||||
LEFT, CENTER, RIGHT = "LEFT", "CENTER", "RIGHT"
|
||||
|
||||
def ljust(x, n):
|
||||
return x.ljust(n)
|
||||
def center(x, n):
|
||||
return x.center(n)
|
||||
def rjust(x, n):
|
||||
return x.rjust(n)
|
||||
align2action = {LEFT: ljust, CENTER: center, RIGHT: rjust}
|
||||
|
||||
align2xml = {LEFT: "left", CENTER: "center", RIGHT: "right"}
|
||||
xml2align = {"left": LEFT, "center": CENTER, "right": RIGHT}
|
||||
|
||||
align2anchor = {LEFT: "w", CENTER: "center", RIGHT: "e"}
|
||||
|
||||
def sum(seq):
|
||||
total = 0
|
||||
for x in seq:
|
||||
if x is not None:
|
||||
total += x
|
||||
return total
|
||||
|
||||
class Sheet:
|
||||
|
||||
def __init__(self):
|
||||
self.cells = {} # {(x, y): cell, ...}
|
||||
self.rexec = rexec.RExec()
|
||||
m = self.rexec.add_module('__main__')
|
||||
m.cell = self.cellvalue
|
||||
m.cells = self.multicellvalue
|
||||
m.sum = sum
|
||||
|
||||
def cellvalue(self, x, y):
|
||||
cell = self.getcell(x, y)
|
||||
if hasattr(cell, 'recalc'):
|
||||
return cell.recalc(self.rexec)
|
||||
else:
|
||||
return cell
|
||||
|
||||
def multicellvalue(self, x1, y1, x2, y2):
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
seq = []
|
||||
for y in range(y1, y2+1):
|
||||
for x in range(x1, x2+1):
|
||||
seq.append(self.cellvalue(x, y))
|
||||
return seq
|
||||
|
||||
def getcell(self, x, y):
|
||||
return self.cells.get((x, y))
|
||||
|
||||
def setcell(self, x, y, cell):
|
||||
assert x > 0 and y > 0
|
||||
assert isinstance(cell, BaseCell)
|
||||
self.cells[x, y] = cell
|
||||
|
||||
def clearcell(self, x, y):
|
||||
try:
|
||||
del self.cells[x, y]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def clearcells(self, x1, y1, x2, y2):
|
||||
for xy in self.selectcells(x1, y1, x2, y2):
|
||||
del self.cells[xy]
|
||||
|
||||
def clearrows(self, y1, y2):
|
||||
self.clearcells(0, y1, sys.maxint, y2)
|
||||
|
||||
def clearcolumns(self, x1, x2):
|
||||
self.clearcells(x1, 0, x2, sys.maxint)
|
||||
|
||||
def selectcells(self, x1, y1, x2, y2):
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
return [(x, y) for x, y in self.cells
|
||||
if x1 <= x <= x2 and y1 <= y <= y2]
|
||||
|
||||
def movecells(self, x1, y1, x2, y2, dx, dy):
|
||||
if dx == 0 and dy == 0:
|
||||
return
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
assert x1+dx > 0 and y1+dy > 0
|
||||
new = {}
|
||||
for x, y in self.cells:
|
||||
cell = self.cells[x, y]
|
||||
if hasattr(cell, 'renumber'):
|
||||
cell = cell.renumber(x1, y1, x2, y2, dx, dy)
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
x += dx
|
||||
y += dy
|
||||
new[x, y] = cell
|
||||
self.cells = new
|
||||
|
||||
def insertrows(self, y, n):
|
||||
assert n > 0
|
||||
self.movecells(0, y, sys.maxint, sys.maxint, 0, n)
|
||||
|
||||
def deleterows(self, y1, y2):
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
self.clearrows(y1, y2)
|
||||
self.movecells(0, y2+1, sys.maxint, sys.maxint, 0, y1-y2-1)
|
||||
|
||||
def insertcolumns(self, x, n):
|
||||
assert n > 0
|
||||
self.movecells(x, 0, sys.maxint, sys.maxint, n, 0)
|
||||
|
||||
def deletecolumns(self, x1, x2):
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
self.clearcells(x1, x2)
|
||||
self.movecells(x2+1, 0, sys.maxint, sys.maxint, x1-x2-1, 0)
|
||||
|
||||
def getsize(self):
|
||||
maxx = maxy = 0
|
||||
for x, y in self.cells:
|
||||
maxx = max(maxx, x)
|
||||
maxy = max(maxy, y)
|
||||
return maxx, maxy
|
||||
|
||||
def reset(self):
|
||||
for cell in self.cells.itervalues():
|
||||
if hasattr(cell, 'reset'):
|
||||
cell.reset()
|
||||
|
||||
def recalc(self):
|
||||
self.reset()
|
||||
for cell in self.cells.itervalues():
|
||||
if hasattr(cell, 'recalc'):
|
||||
cell.recalc(self.rexec)
|
||||
|
||||
def display(self):
|
||||
maxx, maxy = self.getsize()
|
||||
width, height = maxx+1, maxy+1
|
||||
colwidth = [1] * width
|
||||
full = {}
|
||||
# Add column heading labels in row 0
|
||||
for x in range(1, width):
|
||||
full[x, 0] = text, alignment = colnum2name(x), RIGHT
|
||||
colwidth[x] = max(colwidth[x], len(text))
|
||||
# Add row labels in column 0
|
||||
for y in range(1, height):
|
||||
full[0, y] = text, alignment = str(y), RIGHT
|
||||
colwidth[0] = max(colwidth[0], len(text))
|
||||
# Add sheet cells in columns with x>0 and y>0
|
||||
for (x, y), cell in self.cells.iteritems():
|
||||
if x <= 0 or y <= 0:
|
||||
continue
|
||||
if hasattr(cell, 'recalc'):
|
||||
cell.recalc(self.rexec)
|
||||
if hasattr(cell, 'format'):
|
||||
text, alignment = cell.format()
|
||||
assert isinstance(text, str)
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
else:
|
||||
text = str(cell)
|
||||
if isinstance(cell, str):
|
||||
alignment = LEFT
|
||||
else:
|
||||
alignment = RIGHT
|
||||
full[x, y] = (text, alignment)
|
||||
colwidth[x] = max(colwidth[x], len(text))
|
||||
# Calculate the horizontal separator line (dashes and dots)
|
||||
sep = ""
|
||||
for x in range(width):
|
||||
if sep:
|
||||
sep += "+"
|
||||
sep += "-"*colwidth[x]
|
||||
# Now print The full grid
|
||||
for y in range(height):
|
||||
line = ""
|
||||
for x in range(width):
|
||||
text, alignment = full.get((x, y)) or ("", LEFT)
|
||||
text = align2action[alignment](text, colwidth[x])
|
||||
if line:
|
||||
line += '|'
|
||||
line += text
|
||||
print line
|
||||
if y == 0:
|
||||
print sep
|
||||
|
||||
def xml(self):
|
||||
out = ['<spreadsheet>']
|
||||
for (x, y), cell in self.cells.iteritems():
|
||||
if hasattr(cell, 'xml'):
|
||||
cellxml = cell.xml()
|
||||
else:
|
||||
cellxml = '<value>%s</value>' % cgi.escape(cell)
|
||||
out.append('<cell row="%s" col="%s">\n %s\n</cell>' %
|
||||
(y, x, cellxml))
|
||||
out.append('</spreadsheet>')
|
||||
return '\n'.join(out)
|
||||
|
||||
def save(self, filename):
|
||||
text = self.xml()
|
||||
f = open(filename, "w")
|
||||
f.write(text)
|
||||
if text and not text.endswith('\n'):
|
||||
f.write('\n')
|
||||
f.close()
|
||||
|
||||
def load(self, filename):
|
||||
f = open(filename, 'r')
|
||||
SheetParser(self).parsefile(f)
|
||||
f.close()
|
||||
|
||||
class SheetParser:
|
||||
|
||||
def __init__(self, sheet):
|
||||
self.sheet = sheet
|
||||
|
||||
def parsefile(self, f):
|
||||
parser = expat.ParserCreate()
|
||||
parser.StartElementHandler = self.startelement
|
||||
parser.EndElementHandler = self.endelement
|
||||
parser.CharacterDataHandler = self.data
|
||||
parser.ParseFile(f)
|
||||
|
||||
def startelement(self, tag, attrs):
|
||||
method = getattr(self, 'start_'+tag, None)
|
||||
if method:
|
||||
for key, value in attrs.iteritems():
|
||||
attrs[key] = str(value) # XXX Convert Unicode to 8-bit
|
||||
method(attrs)
|
||||
self.texts = []
|
||||
|
||||
def data(self, text):
|
||||
text = str(text) # XXX Convert Unicode to 8-bit
|
||||
self.texts.append(text)
|
||||
|
||||
def endelement(self, tag):
|
||||
method = getattr(self, 'end_'+tag, None)
|
||||
if method:
|
||||
method("".join(self.texts))
|
||||
|
||||
def start_cell(self, attrs):
|
||||
self.y = int(attrs.get("row"))
|
||||
self.x = int(attrs.get("col"))
|
||||
|
||||
def start_value(self, attrs):
|
||||
self.fmt = attrs.get('format')
|
||||
self.alignment = xml2align.get(attrs.get('align'))
|
||||
|
||||
start_formula = start_value
|
||||
|
||||
def end_int(self, text):
|
||||
try:
|
||||
self.value = int(text)
|
||||
except:
|
||||
self.value = None
|
||||
|
||||
def end_long(self, text):
|
||||
try:
|
||||
self.value = long(text)
|
||||
except:
|
||||
self.value = None
|
||||
|
||||
def end_double(self, text):
|
||||
try:
|
||||
self.value = float(text)
|
||||
except:
|
||||
self.value = None
|
||||
|
||||
def end_complex(self, text):
|
||||
try:
|
||||
self.value = complex(text)
|
||||
except:
|
||||
self.value = None
|
||||
|
||||
def end_string(self, text):
|
||||
try:
|
||||
self.value = text
|
||||
except:
|
||||
self.value = None
|
||||
|
||||
def end_value(self, text):
|
||||
if isinstance(self.value, BaseCell):
|
||||
self.cell = self.value
|
||||
elif isinstance(self.value, str):
|
||||
self.cell = StringCell(self.value,
|
||||
self.fmt or "%s",
|
||||
self.alignment or LEFT)
|
||||
else:
|
||||
self.cell = NumericCell(self.value,
|
||||
self.fmt or "%s",
|
||||
self.alignment or RIGHT)
|
||||
|
||||
def end_formula(self, text):
|
||||
self.cell = FormulaCell(text,
|
||||
self.fmt or "%s",
|
||||
self.alignment or RIGHT)
|
||||
|
||||
def end_cell(self, text):
|
||||
self.sheet.setcell(self.x, self.y, self.cell)
|
||||
|
||||
class BaseCell:
|
||||
__init__ = None # Must provide
|
||||
"""Abstract base class for sheet cells.
|
||||
|
||||
Subclasses may but needn't provide the following APIs:
|
||||
|
||||
cell.reset() -- prepare for recalculation
|
||||
cell.recalc(rexec) -> value -- recalculate formula
|
||||
cell.format() -> (value, alignment) -- return formatted value
|
||||
cell.xml() -> string -- return XML
|
||||
"""
|
||||
|
||||
class NumericCell(BaseCell):
|
||||
|
||||
def __init__(self, value, fmt="%s", alignment=RIGHT):
|
||||
assert isinstance(value, (int, long, float, complex))
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
self.value = value
|
||||
self.fmt = fmt
|
||||
self.alignment = alignment
|
||||
|
||||
def recalc(self, rexec):
|
||||
return self.value
|
||||
|
||||
def format(self):
|
||||
try:
|
||||
text = self.fmt % self.value
|
||||
except:
|
||||
text = str(self.value)
|
||||
return text, self.alignment
|
||||
|
||||
def xml(self):
|
||||
method = getattr(self, '_xml_' + type(self.value).__name__)
|
||||
return '<value align="%s" format="%s">%s</value>' % (
|
||||
align2xml[self.alignment],
|
||||
self.fmt,
|
||||
method())
|
||||
|
||||
def _xml_int(self):
|
||||
if -2**31 <= self.value < 2**31:
|
||||
return '<int>%s</int>' % self.value
|
||||
else:
|
||||
return self._xml_long()
|
||||
|
||||
def _xml_long(self):
|
||||
return '<long>%s</long>' % self.value
|
||||
|
||||
def _xml_float(self):
|
||||
return '<double>%s</double>' % repr(self.value)
|
||||
|
||||
def _xml_complex(self):
|
||||
return '<complex>%s</double>' % repr(self.value)
|
||||
|
||||
class StringCell(BaseCell):
|
||||
|
||||
def __init__(self, text, fmt="%s", alignment=LEFT):
|
||||
assert isinstance(text, (str, unicode))
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
self.text = text
|
||||
self.fmt = fmt
|
||||
self.alignment = alignment
|
||||
|
||||
def recalc(self, rexec):
|
||||
return self.text
|
||||
|
||||
def format(self):
|
||||
return self.text, self.alignment
|
||||
|
||||
def xml(self):
|
||||
s = '<value align="%s" format="%s"><string>%s</string></value>'
|
||||
return s % (
|
||||
align2xml[self.alignment],
|
||||
self.fmt,
|
||||
cgi.escape(self.text))
|
||||
|
||||
class FormulaCell(BaseCell):
|
||||
|
||||
def __init__(self, formula, fmt="%s", alignment=RIGHT):
|
||||
assert alignment in (LEFT, CENTER, RIGHT)
|
||||
self.formula = formula
|
||||
self.translated = translate(self.formula)
|
||||
self.fmt = fmt
|
||||
self.alignment = alignment
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self.value = None
|
||||
|
||||
def recalc(self, rexec):
|
||||
if self.value is None:
|
||||
try:
|
||||
# A hack to evaluate expressions using true division
|
||||
rexec.r_exec("from __future__ import division\n" +
|
||||
"__value__ = eval(%s)" % repr(self.translated))
|
||||
self.value = rexec.r_eval("__value__")
|
||||
except:
|
||||
exc = sys.exc_info()[0]
|
||||
if hasattr(exc, "__name__"):
|
||||
self.value = exc.__name__
|
||||
else:
|
||||
self.value = str(exc)
|
||||
return self.value
|
||||
|
||||
def format(self):
|
||||
try:
|
||||
text = self.fmt % self.value
|
||||
except:
|
||||
text = str(self.value)
|
||||
return text, self.alignment
|
||||
|
||||
def xml(self):
|
||||
return '<formula align="%s" format="%s">%s</formula>' % (
|
||||
align2xml[self.alignment],
|
||||
self.fmt,
|
||||
self.formula)
|
||||
|
||||
def renumber(self, x1, y1, x2, y2, dx, dy):
|
||||
out = []
|
||||
for part in re.split('(\w+)', self.formula):
|
||||
m = re.match('^([A-Z]+)([1-9][0-9]*)$', part)
|
||||
if m is not None:
|
||||
sx, sy = m.groups()
|
||||
x = colname2num(sx)
|
||||
y = int(sy)
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
part = cellname(x+dx, y+dy)
|
||||
out.append(part)
|
||||
return FormulaCell("".join(out), self.fmt, self.alignment)
|
||||
|
||||
def translate(formula):
|
||||
"""Translate a formula containing fancy cell names to valid Python code.
|
||||
|
||||
Examples:
|
||||
B4 -> cell(2, 4)
|
||||
B4:Z100 -> cells(2, 4, 26, 100)
|
||||
"""
|
||||
out = []
|
||||
for part in re.split(r"(\w+(?::\w+)?)", formula):
|
||||
m = re.match(r"^([A-Z]+)([1-9][0-9]*)(?::([A-Z]+)([1-9][0-9]*))?$", part)
|
||||
if m is None:
|
||||
out.append(part)
|
||||
else:
|
||||
x1, y1, x2, y2 = m.groups()
|
||||
x1 = colname2num(x1)
|
||||
if x2 is None:
|
||||
s = "cell(%s, %s)" % (x1, y1)
|
||||
else:
|
||||
x2 = colname2num(x2)
|
||||
s = "cells(%s, %s, %s, %s)" % (x1, y1, x2, y2)
|
||||
out.append(s)
|
||||
return "".join(out)
|
||||
|
||||
def cellname(x, y):
|
||||
"Translate a cell coordinate to a fancy cell name (e.g. (1, 1)->'A1')."
|
||||
assert x > 0 # Column 0 has an empty name, so can't use that
|
||||
return colnum2name(x) + str(y)
|
||||
|
||||
def colname2num(s):
|
||||
"Translate a column name to number (e.g. 'A'->1, 'Z'->26, 'AA'->27)."
|
||||
s = s.upper()
|
||||
n = 0
|
||||
for c in s:
|
||||
assert 'A' <= c <= 'Z'
|
||||
n = n*26 + ord(c) - ord('A') + 1
|
||||
return n
|
||||
|
||||
def colnum2name(n):
|
||||
"Translate a column number to name (e.g. 1->'A', etc.)."
|
||||
assert n > 0
|
||||
s = ""
|
||||
while n:
|
||||
n, m = divmod(n-1, 26)
|
||||
s = chr(m+ord('A')) + s
|
||||
return s
|
||||
|
||||
import Tkinter as Tk
|
||||
|
||||
class SheetGUI:
|
||||
|
||||
"""Beginnings of a GUI for a spreadsheet.
|
||||
|
||||
TO DO:
|
||||
- clear multiple cells
|
||||
- Insert, clear, remove rows or columns
|
||||
- Show new contents while typing
|
||||
- Scroll bars
|
||||
- Grow grid when window is grown
|
||||
- Proper menus
|
||||
- Undo, redo
|
||||
- Cut, copy and paste
|
||||
- Formatting and alignment
|
||||
"""
|
||||
|
||||
def __init__(self, filename="sheet1.xml", rows=10, columns=5):
|
||||
"""Constructor.
|
||||
|
||||
Load the sheet from the filename argument.
|
||||
Set up the Tk widget tree.
|
||||
"""
|
||||
# Create and load the sheet
|
||||
self.filename = filename
|
||||
self.sheet = Sheet()
|
||||
if os.path.isfile(filename):
|
||||
self.sheet.load(filename)
|
||||
# Calculate the needed grid size
|
||||
maxx, maxy = self.sheet.getsize()
|
||||
rows = max(rows, maxy)
|
||||
columns = max(columns, maxx)
|
||||
# Create the widgets
|
||||
self.root = Tk.Tk()
|
||||
self.root.wm_title("Spreadsheet: %s" % self.filename)
|
||||
self.beacon = Tk.Label(self.root, text="A1",
|
||||
font=('helvetica', 16, 'bold'))
|
||||
self.entry = Tk.Entry(self.root)
|
||||
self.savebutton = Tk.Button(self.root, text="Save",
|
||||
command=self.save)
|
||||
self.cellgrid = Tk.Frame(self.root)
|
||||
# Configure the widget lay-out
|
||||
self.cellgrid.pack(side="bottom", expand=1, fill="both")
|
||||
self.beacon.pack(side="left")
|
||||
self.savebutton.pack(side="right")
|
||||
self.entry.pack(side="left", expand=1, fill="x")
|
||||
# Bind some events
|
||||
self.entry.bind("<Return>", self.return_event)
|
||||
self.entry.bind("<Shift-Return>", self.shift_return_event)
|
||||
self.entry.bind("<Tab>", self.tab_event)
|
||||
self.entry.bind("<Shift-Tab>", self.shift_tab_event)
|
||||
self.entry.bind("<Delete>", self.delete_event)
|
||||
self.entry.bind("<Escape>", self.escape_event)
|
||||
# Now create the cell grid
|
||||
self.makegrid(rows, columns)
|
||||
# Select the top-left cell
|
||||
self.currentxy = None
|
||||
self.cornerxy = None
|
||||
self.setcurrent(1, 1)
|
||||
# Copy the sheet cells to the GUI cells
|
||||
self.sync()
|
||||
|
||||
def delete_event(self, event):
|
||||
if self.cornerxy != self.currentxy and self.cornerxy is not None:
|
||||
self.sheet.clearcells(*(self.currentxy + self.cornerxy))
|
||||
else:
|
||||
self.sheet.clearcell(*self.currentxy)
|
||||
self.sync()
|
||||
self.entry.delete(0, 'end')
|
||||
return "break"
|
||||
|
||||
def escape_event(self, event):
|
||||
x, y = self.currentxy
|
||||
self.load_entry(x, y)
|
||||
|
||||
def load_entry(self, x, y):
|
||||
cell = self.sheet.getcell(x, y)
|
||||
if cell is None:
|
||||
text = ""
|
||||
elif isinstance(cell, FormulaCell):
|
||||
text = '=' + cell.formula
|
||||
else:
|
||||
text, alignment = cell.format()
|
||||
self.entry.delete(0, 'end')
|
||||
self.entry.insert(0, text)
|
||||
self.entry.selection_range(0, 'end')
|
||||
|
||||
def makegrid(self, rows, columns):
|
||||
"""Helper to create the grid of GUI cells.
|
||||
|
||||
The edge (x==0 or y==0) is filled with labels; the rest is real cells.
|
||||
"""
|
||||
self.rows = rows
|
||||
self.columns = columns
|
||||
self.gridcells = {}
|
||||
# Create the top left corner cell (which selects all)
|
||||
cell = Tk.Label(self.cellgrid, relief='raised')
|
||||
cell.grid_configure(column=0, row=0, sticky='NSWE')
|
||||
cell.bind("<ButtonPress-1>", self.selectall)
|
||||
# Create the top row of labels, and confiure the grid columns
|
||||
for x in range(1, columns+1):
|
||||
self.cellgrid.grid_columnconfigure(x, minsize=64)
|
||||
cell = Tk.Label(self.cellgrid, text=colnum2name(x), relief='raised')
|
||||
cell.grid_configure(column=x, row=0, sticky='WE')
|
||||
self.gridcells[x, 0] = cell
|
||||
cell.__x = x
|
||||
cell.__y = 0
|
||||
cell.bind("<ButtonPress-1>", self.selectcolumn)
|
||||
cell.bind("<B1-Motion>", self.extendcolumn)
|
||||
cell.bind("<ButtonRelease-1>", self.extendcolumn)
|
||||
cell.bind("<Shift-Button-1>", self.extendcolumn)
|
||||
# Create the leftmost column of labels
|
||||
for y in range(1, rows+1):
|
||||
cell = Tk.Label(self.cellgrid, text=str(y), relief='raised')
|
||||
cell.grid_configure(column=0, row=y, sticky='WE')
|
||||
self.gridcells[0, y] = cell
|
||||
cell.__x = 0
|
||||
cell.__y = y
|
||||
cell.bind("<ButtonPress-1>", self.selectrow)
|
||||
cell.bind("<B1-Motion>", self.extendrow)
|
||||
cell.bind("<ButtonRelease-1>", self.extendrow)
|
||||
cell.bind("<Shift-Button-1>", self.extendrow)
|
||||
# Create the real cells
|
||||
for x in range(1, columns+1):
|
||||
for y in range(1, rows+1):
|
||||
cell = Tk.Label(self.cellgrid, relief='sunken',
|
||||
bg='white', fg='black')
|
||||
cell.grid_configure(column=x, row=y, sticky='NSWE')
|
||||
self.gridcells[x, y] = cell
|
||||
cell.__x = x
|
||||
cell.__y = y
|
||||
# Bind mouse events
|
||||
cell.bind("<ButtonPress-1>", self.press)
|
||||
cell.bind("<B1-Motion>", self.motion)
|
||||
cell.bind("<ButtonRelease-1>", self.release)
|
||||
cell.bind("<Shift-Button-1>", self.release)
|
||||
|
||||
def selectall(self, event):
|
||||
self.setcurrent(1, 1)
|
||||
self.setcorner(sys.maxint, sys.maxint)
|
||||
|
||||
def selectcolumn(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
self.setcurrent(x, 1)
|
||||
self.setcorner(x, sys.maxint)
|
||||
|
||||
def extendcolumn(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if x > 0:
|
||||
self.setcurrent(self.currentxy[0], 1)
|
||||
self.setcorner(x, sys.maxint)
|
||||
|
||||
def selectrow(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
self.setcurrent(1, y)
|
||||
self.setcorner(sys.maxint, y)
|
||||
|
||||
def extendrow(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if y > 0:
|
||||
self.setcurrent(1, self.currentxy[1])
|
||||
self.setcorner(sys.maxint, y)
|
||||
|
||||
def press(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if x > 0 and y > 0:
|
||||
self.setcurrent(x, y)
|
||||
|
||||
def motion(self, event):
|
||||
x, y = self.whichxy(event)
|
||||
if x > 0 and y > 0:
|
||||
self.setcorner(x, y)
|
||||
|
||||
release = motion
|
||||
|
||||
def whichxy(self, event):
|
||||
w = self.cellgrid.winfo_containing(event.x_root, event.y_root)
|
||||
if w is not None and isinstance(w, Tk.Label):
|
||||
try:
|
||||
return w.__x, w.__y
|
||||
except AttributeError:
|
||||
pass
|
||||
return 0, 0
|
||||
|
||||
def save(self):
|
||||
self.sheet.save(self.filename)
|
||||
|
||||
def setcurrent(self, x, y):
|
||||
"Make (x, y) the current cell."
|
||||
if self.currentxy is not None:
|
||||
self.change_cell()
|
||||
self.clearfocus()
|
||||
self.beacon['text'] = cellname(x, y)
|
||||
self.load_entry(x, y)
|
||||
self.entry.focus_set()
|
||||
self.currentxy = x, y
|
||||
self.cornerxy = None
|
||||
gridcell = self.gridcells.get(self.currentxy)
|
||||
if gridcell is not None:
|
||||
gridcell['bg'] = 'yellow'
|
||||
|
||||
def setcorner(self, x, y):
|
||||
if self.currentxy is None or self.currentxy == (x, y):
|
||||
self.setcurrent(x, y)
|
||||
return
|
||||
self.clearfocus()
|
||||
self.cornerxy = x, y
|
||||
x1, y1 = self.currentxy
|
||||
x2, y2 = self.cornerxy or self.currentxy
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
for (x, y), cell in self.gridcells.iteritems():
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
cell['bg'] = 'lightBlue'
|
||||
gridcell = self.gridcells.get(self.currentxy)
|
||||
if gridcell is not None:
|
||||
gridcell['bg'] = 'yellow'
|
||||
self.setbeacon(x1, y1, x2, y2)
|
||||
|
||||
def setbeacon(self, x1, y1, x2, y2):
|
||||
if x1 == y1 == 1 and x2 == y2 == sys.maxint:
|
||||
name = ":"
|
||||
elif (x1, x2) == (1, sys.maxint):
|
||||
if y1 == y2:
|
||||
name = "%d" % y1
|
||||
else:
|
||||
name = "%d:%d" % (y1, y2)
|
||||
elif (y1, y2) == (1, sys.maxint):
|
||||
if x1 == x2:
|
||||
name = "%s" % colnum2name(x1)
|
||||
else:
|
||||
name = "%s:%s" % (colnum2name(x1), colnum2name(x2))
|
||||
else:
|
||||
name1 = cellname(*self.currentxy)
|
||||
name2 = cellname(*self.cornerxy)
|
||||
name = "%s:%s" % (name1, name2)
|
||||
self.beacon['text'] = name
|
||||
|
||||
|
||||
def clearfocus(self):
|
||||
if self.currentxy is not None:
|
||||
x1, y1 = self.currentxy
|
||||
x2, y2 = self.cornerxy or self.currentxy
|
||||
if x1 > x2:
|
||||
x1, x2 = x2, x1
|
||||
if y1 > y2:
|
||||
y1, y2 = y2, y1
|
||||
for (x, y), cell in self.gridcells.iteritems():
|
||||
if x1 <= x <= x2 and y1 <= y <= y2:
|
||||
cell['bg'] = 'white'
|
||||
|
||||
def return_event(self, event):
|
||||
"Callback for the Return key."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(x, y+1)
|
||||
return "break"
|
||||
|
||||
def shift_return_event(self, event):
|
||||
"Callback for the Return key with Shift modifier."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(x, max(1, y-1))
|
||||
return "break"
|
||||
|
||||
def tab_event(self, event):
|
||||
"Callback for the Tab key."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(x+1, y)
|
||||
return "break"
|
||||
|
||||
def shift_tab_event(self, event):
|
||||
"Callback for the Tab key with Shift modifier."
|
||||
self.change_cell()
|
||||
x, y = self.currentxy
|
||||
self.setcurrent(max(1, x-1), y)
|
||||
return "break"
|
||||
|
||||
def change_cell(self):
|
||||
"Set the current cell from the entry widget."
|
||||
x, y = self.currentxy
|
||||
text = self.entry.get()
|
||||
cell = None
|
||||
if text.startswith('='):
|
||||
cell = FormulaCell(text[1:])
|
||||
else:
|
||||
for cls in int, long, float, complex:
|
||||
try:
|
||||
value = cls(text)
|
||||
except:
|
||||
continue
|
||||
else:
|
||||
cell = NumericCell(value)
|
||||
break
|
||||
if cell is None and text:
|
||||
cell = StringCell(text)
|
||||
if cell is None:
|
||||
self.sheet.clearcell(x, y)
|
||||
else:
|
||||
self.sheet.setcell(x, y, cell)
|
||||
self.sync()
|
||||
|
||||
def sync(self):
|
||||
"Fill the GUI cells from the sheet cells."
|
||||
self.sheet.recalc()
|
||||
for (x, y), gridcell in self.gridcells.iteritems():
|
||||
if x == 0 or y == 0:
|
||||
continue
|
||||
cell = self.sheet.getcell(x, y)
|
||||
if cell is None:
|
||||
gridcell['text'] = ""
|
||||
else:
|
||||
if hasattr(cell, 'format'):
|
||||
text, alignment = cell.format()
|
||||
else:
|
||||
text, alignment = str(cell), LEFT
|
||||
gridcell['text'] = text
|
||||
gridcell['anchor'] = align2anchor[alignment]
|
||||
|
||||
|
||||
def test_basic():
|
||||
"Basic non-gui self-test."
|
||||
import os
|
||||
a = Sheet()
|
||||
for x in range(1, 11):
|
||||
for y in range(1, 11):
|
||||
if x == 1:
|
||||
cell = NumericCell(y)
|
||||
elif y == 1:
|
||||
cell = NumericCell(x)
|
||||
else:
|
||||
c1 = cellname(x, 1)
|
||||
c2 = cellname(1, y)
|
||||
formula = "%s*%s" % (c1, c2)
|
||||
cell = FormulaCell(formula)
|
||||
a.setcell(x, y, cell)
|
||||
## if os.path.isfile("sheet1.xml"):
|
||||
## print "Loading from sheet1.xml"
|
||||
## a.load("sheet1.xml")
|
||||
a.display()
|
||||
a.save("sheet1.xml")
|
||||
|
||||
def test_gui():
|
||||
"GUI test."
|
||||
if sys.argv[1:]:
|
||||
filename = sys.argv[1]
|
||||
else:
|
||||
filename = "sheet1.xml"
|
||||
g = SheetGUI(filename)
|
||||
g.root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
#test_basic()
|
||||
test_gui()
|
||||
128
Demo/tkinter/guido/svkill.py
Executable file
128
Demo/tkinter/guido/svkill.py
Executable file
@@ -0,0 +1,128 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# Tkinter interface to SYSV `ps' and `kill' commands.
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
if TkVersion < 4.0:
|
||||
raise ImportError, "This version of svkill requires Tk 4.0 or later"
|
||||
|
||||
from string import splitfields
|
||||
from string import split
|
||||
import commands
|
||||
import os
|
||||
|
||||
user = os.environ['LOGNAME']
|
||||
|
||||
class BarButton(Menubutton):
|
||||
def __init__(self, master=None, **cnf):
|
||||
apply(Menubutton.__init__, (self, master), cnf)
|
||||
self.pack(side=LEFT)
|
||||
self.menu = Menu(self, name='menu')
|
||||
self['menu'] = self.menu
|
||||
|
||||
class Kill(Frame):
|
||||
# List of (name, option, pid_column)
|
||||
view_list = [
|
||||
('Default', ''),
|
||||
('Every (-e)', '-e'),
|
||||
('Non process group leaders (-d)', '-d'),
|
||||
('Non leaders with tty (-a)', '-a'),
|
||||
('For this user (-u %s)' % user, '-u %s' % user),
|
||||
]
|
||||
format_list = [
|
||||
('Default', '', 0),
|
||||
('Long (-l)', '-l', 3),
|
||||
('Full (-f)', '-f', 1),
|
||||
('Full Long (-f -l)', '-l -f', 3),
|
||||
('Session and group ID (-j)', '-j', 0),
|
||||
('Scheduler properties (-c)', '-c', 0),
|
||||
]
|
||||
def kill(self, selected):
|
||||
c = self.format_list[self.format.get()][2]
|
||||
pid = split(selected)[c]
|
||||
os.system('kill -9 ' + pid)
|
||||
self.do_update()
|
||||
def do_update(self):
|
||||
format = self.format_list[self.format.get()][1]
|
||||
view = self.view_list[self.view.get()][1]
|
||||
s = commands.getoutput('ps %s %s' % (view, format))
|
||||
list = splitfields(s, '\n')
|
||||
self.header.set(list[0] + ' ')
|
||||
del list[0]
|
||||
self.frame.list.delete(0, AtEnd())
|
||||
for line in list:
|
||||
self.frame.list.insert(0, line)
|
||||
def do_motion(self, e):
|
||||
e.widget.select_clear('0', 'end')
|
||||
e.widget.select_set(e.widget.nearest(e.y))
|
||||
def do_leave(self, e):
|
||||
e.widget.select_clear('0', 'end')
|
||||
def do_1(self, e):
|
||||
self.kill(e.widget.get(e.widget.nearest(e.y)))
|
||||
def __init__(self, master=None, **cnf):
|
||||
apply(Frame.__init__, (self, master), cnf)
|
||||
self.pack(expand=1, fill=BOTH)
|
||||
self.bar = Frame(self, name='bar', relief=RAISED,
|
||||
borderwidth=2)
|
||||
self.bar.pack(fill=X)
|
||||
self.bar.file = BarButton(self.bar, text='File')
|
||||
self.bar.file.menu.add_command(
|
||||
label='Quit', command=self.quit)
|
||||
self.bar.view = BarButton(self.bar, text='View')
|
||||
self.bar.format = BarButton(self.bar, text='Format')
|
||||
self.view = IntVar(self)
|
||||
self.view.set(0)
|
||||
self.format = IntVar(self)
|
||||
self.format.set(0)
|
||||
for num in range(len(self.view_list)):
|
||||
label, option = self.view_list[num]
|
||||
self.bar.view.menu.add_radiobutton(
|
||||
label=label,
|
||||
command=self.do_update,
|
||||
variable=self.view,
|
||||
value=num)
|
||||
for num in range(len(self.format_list)):
|
||||
label, option, col = self.format_list[num]
|
||||
self.bar.format.menu.add_radiobutton(
|
||||
label=label,
|
||||
command=self.do_update,
|
||||
variable=self.format,
|
||||
value=num)
|
||||
self.bar.tk_menuBar(self.bar.file,
|
||||
self.bar.view,
|
||||
self.bar.format)
|
||||
self.frame = Frame(self, relief=RAISED, borderwidth=2)
|
||||
self.frame.pack(expand=1, fill=BOTH)
|
||||
self.header = StringVar(self)
|
||||
self.frame.label = Label(
|
||||
self.frame, relief=FLAT, anchor=NW, borderwidth=0,
|
||||
font='*-Courier-Bold-R-Normal-*-120-*',
|
||||
textvariable=self.header)
|
||||
self.frame.label.pack(fill=Y, anchor=W)
|
||||
self.frame.vscroll = Scrollbar(self.frame, orient=VERTICAL)
|
||||
self.frame.list = Listbox(
|
||||
self.frame,
|
||||
relief=SUNKEN,
|
||||
font='*-Courier-Medium-R-Normal-*-120-*',
|
||||
width=40, height=10,
|
||||
selectbackground='#eed5b7',
|
||||
selectborderwidth=0,
|
||||
selectmode=BROWSE,
|
||||
yscroll=self.frame.vscroll.set)
|
||||
self.frame.vscroll['command'] = self.frame.list.yview
|
||||
self.frame.vscroll.pack(side=RIGHT, fill=Y)
|
||||
self.frame.list.pack(expand=1, fill=BOTH)
|
||||
self.update = Button(self, text='Update',
|
||||
command=self.do_update)
|
||||
self.update.pack(fill=X)
|
||||
self.frame.list.bind('<Motion>', self.do_motion)
|
||||
self.frame.list.bind('<Leave>', self.do_leave)
|
||||
self.frame.list.bind('<1>', self.do_1)
|
||||
self.do_update()
|
||||
|
||||
if __name__ == '__main__':
|
||||
kill = Kill(None, borderwidth=5)
|
||||
kill.winfo_toplevel().title('Tkinter Process Killer (SYSV)')
|
||||
kill.winfo_toplevel().minsize(1, 1)
|
||||
kill.mainloop()
|
||||
55
Demo/tkinter/guido/switch.py
Normal file
55
Demo/tkinter/guido/switch.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# Show how to do switchable panels.
|
||||
|
||||
from Tkinter import *
|
||||
|
||||
class App:
|
||||
|
||||
def __init__(self, top=None, master=None):
|
||||
if top is None:
|
||||
if master is None:
|
||||
top = Tk()
|
||||
else:
|
||||
top = Toplevel(master)
|
||||
self.top = top
|
||||
self.buttonframe = Frame(top)
|
||||
self.buttonframe.pack()
|
||||
self.panelframe = Frame(top, borderwidth=2, relief=GROOVE)
|
||||
self.panelframe.pack(expand=1, fill=BOTH)
|
||||
self.panels = {}
|
||||
self.curpanel = None
|
||||
|
||||
def addpanel(self, name, klass):
|
||||
button = Button(self.buttonframe, text=name,
|
||||
command=lambda self=self, name=name: self.show(name))
|
||||
button.pack(side=LEFT)
|
||||
frame = Frame(self.panelframe)
|
||||
instance = klass(frame)
|
||||
self.panels[name] = (button, frame, instance)
|
||||
if self.curpanel is None:
|
||||
self.show(name)
|
||||
|
||||
def show(self, name):
|
||||
(button, frame, instance) = self.panels[name]
|
||||
if self.curpanel:
|
||||
self.curpanel.pack_forget()
|
||||
self.curpanel = frame
|
||||
frame.pack(expand=1, fill="both")
|
||||
|
||||
class LabelPanel:
|
||||
def __init__(self, frame):
|
||||
self.label = Label(frame, text="Hello world")
|
||||
self.label.pack()
|
||||
|
||||
class ButtonPanel:
|
||||
def __init__(self, frame):
|
||||
self.button = Button(frame, text="Press me")
|
||||
self.button.pack()
|
||||
|
||||
def main():
|
||||
app = App()
|
||||
app.addpanel("label", LabelPanel)
|
||||
app.addpanel("button", ButtonPanel)
|
||||
app.top.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
267
Demo/tkinter/guido/tkman.py
Executable file
267
Demo/tkinter/guido/tkman.py
Executable file
@@ -0,0 +1,267 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# Tk man page browser -- currently only shows the Tcl/Tk man pages
|
||||
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
import re
|
||||
from Tkinter import *
|
||||
from ManPage import ManPage
|
||||
|
||||
MANNDIRLIST = ['/depot/sundry/man/mann','/usr/local/man/mann']
|
||||
MAN3DIRLIST = ['/depot/sundry/man/man3','/usr/local/man/man3']
|
||||
|
||||
foundmanndir = 0
|
||||
for dir in MANNDIRLIST:
|
||||
if os.path.exists(dir):
|
||||
MANNDIR = dir
|
||||
foundmanndir = 1
|
||||
|
||||
foundman3dir = 0
|
||||
for dir in MAN3DIRLIST:
|
||||
if os.path.exists(dir):
|
||||
MAN3DIR = dir
|
||||
foundman3dir = 1
|
||||
|
||||
if not foundmanndir or not foundman3dir:
|
||||
sys.stderr.write('\n')
|
||||
if not foundmanndir:
|
||||
msg = """\
|
||||
Failed to find mann directory.
|
||||
Please add the correct entry to the MANNDIRLIST
|
||||
at the top of %s script.""" % \
|
||||
sys.argv[0]
|
||||
sys.stderr.write("%s\n\n" % msg)
|
||||
if not foundman3dir:
|
||||
msg = """\
|
||||
Failed to find man3 directory.
|
||||
Please add the correct entry to the MAN3DIRLIST
|
||||
at the top of %s script.""" % \
|
||||
sys.argv[0]
|
||||
sys.stderr.write("%s\n\n" % msg)
|
||||
sys.exit(1)
|
||||
|
||||
del foundmanndir
|
||||
del foundman3dir
|
||||
|
||||
def listmanpages(mandir):
|
||||
files = os.listdir(mandir)
|
||||
names = []
|
||||
for file in files:
|
||||
if file[-2:-1] == '.' and (file[-1] in 'ln123456789'):
|
||||
names.append(file[:-2])
|
||||
names.sort()
|
||||
return names
|
||||
|
||||
class SelectionBox:
|
||||
|
||||
def __init__(self, master=None):
|
||||
self.choices = []
|
||||
|
||||
self.frame = Frame(master, name="frame")
|
||||
self.frame.pack(expand=1, fill=BOTH)
|
||||
self.master = self.frame.master
|
||||
self.subframe = Frame(self.frame, name="subframe")
|
||||
self.subframe.pack(expand=0, fill=BOTH)
|
||||
self.leftsubframe = Frame(self.subframe, name='leftsubframe')
|
||||
self.leftsubframe.pack(side=LEFT, expand=1, fill=BOTH)
|
||||
self.rightsubframe = Frame(self.subframe, name='rightsubframe')
|
||||
self.rightsubframe.pack(side=RIGHT, expand=1, fill=BOTH)
|
||||
self.chaptervar = StringVar(master)
|
||||
self.chapter = Menubutton(self.rightsubframe, name='chapter',
|
||||
text='Directory', relief=RAISED,
|
||||
borderwidth=2)
|
||||
self.chapter.pack(side=TOP)
|
||||
self.chaptermenu = Menu(self.chapter, name='chaptermenu')
|
||||
self.chaptermenu.add_radiobutton(label='C functions',
|
||||
value=MAN3DIR,
|
||||
variable=self.chaptervar,
|
||||
command=self.newchapter)
|
||||
self.chaptermenu.add_radiobutton(label='Tcl/Tk functions',
|
||||
value=MANNDIR,
|
||||
variable=self.chaptervar,
|
||||
command=self.newchapter)
|
||||
self.chapter['menu'] = self.chaptermenu
|
||||
self.listbox = Listbox(self.rightsubframe, name='listbox',
|
||||
relief=SUNKEN, borderwidth=2,
|
||||
width=20, height=5)
|
||||
self.listbox.pack(expand=1, fill=BOTH)
|
||||
self.l1 = Button(self.leftsubframe, name='l1',
|
||||
text='Display manual page named:',
|
||||
command=self.entry_cb)
|
||||
self.l1.pack(side=TOP)
|
||||
self.entry = Entry(self.leftsubframe, name='entry',
|
||||
relief=SUNKEN, borderwidth=2,
|
||||
width=20)
|
||||
self.entry.pack(expand=0, fill=X)
|
||||
self.l2frame = Frame(self.leftsubframe, name='l2frame')
|
||||
self.l2frame.pack(expand=0, fill=NONE)
|
||||
self.l2 = Button(self.l2frame, name='l2',
|
||||
text='Search regexp:',
|
||||
command=self.search_cb)
|
||||
self.l2.pack(side=LEFT)
|
||||
self.casevar = BooleanVar()
|
||||
self.casesense = Checkbutton(self.l2frame, name='casesense',
|
||||
text='Case sensitive',
|
||||
variable=self.casevar,
|
||||
relief=FLAT)
|
||||
self.casesense.pack(side=LEFT)
|
||||
self.search = Entry(self.leftsubframe, name='search',
|
||||
relief=SUNKEN, borderwidth=2,
|
||||
width=20)
|
||||
self.search.pack(expand=0, fill=X)
|
||||
self.title = Label(self.leftsubframe, name='title',
|
||||
text='(none)')
|
||||
self.title.pack(side=BOTTOM)
|
||||
self.text = ManPage(self.frame, name='text',
|
||||
relief=SUNKEN, borderwidth=2,
|
||||
wrap=NONE, width=72,
|
||||
selectbackground='pink')
|
||||
self.text.pack(expand=1, fill=BOTH)
|
||||
|
||||
self.entry.bind('<Return>', self.entry_cb)
|
||||
self.search.bind('<Return>', self.search_cb)
|
||||
self.listbox.bind('<Double-1>', self.listbox_cb)
|
||||
|
||||
self.entry.bind('<Tab>', self.entry_tab)
|
||||
self.search.bind('<Tab>', self.search_tab)
|
||||
self.text.bind('<Tab>', self.text_tab)
|
||||
|
||||
self.entry.focus_set()
|
||||
|
||||
self.chaptervar.set(MANNDIR)
|
||||
self.newchapter()
|
||||
|
||||
def newchapter(self):
|
||||
mandir = self.chaptervar.get()
|
||||
self.choices = []
|
||||
self.addlist(listmanpages(mandir))
|
||||
|
||||
def addchoice(self, choice):
|
||||
if choice not in self.choices:
|
||||
self.choices.append(choice)
|
||||
self.choices.sort()
|
||||
self.update()
|
||||
|
||||
def addlist(self, list):
|
||||
self.choices[len(self.choices):] = list
|
||||
self.choices.sort()
|
||||
self.update()
|
||||
|
||||
def entry_cb(self, *e):
|
||||
self.update()
|
||||
|
||||
def listbox_cb(self, e):
|
||||
selection = self.listbox.curselection()
|
||||
if selection and len(selection) == 1:
|
||||
name = self.listbox.get(selection[0])
|
||||
self.show_page(name)
|
||||
|
||||
def search_cb(self, *e):
|
||||
self.search_string(self.search.get())
|
||||
|
||||
def entry_tab(self, e):
|
||||
self.search.focus_set()
|
||||
|
||||
def search_tab(self, e):
|
||||
self.entry.focus_set()
|
||||
|
||||
def text_tab(self, e):
|
||||
self.entry.focus_set()
|
||||
|
||||
def updatelist(self):
|
||||
key = self.entry.get()
|
||||
ok = filter(lambda name, key=key, n=len(key): name[:n]==key,
|
||||
self.choices)
|
||||
if not ok:
|
||||
self.frame.bell()
|
||||
self.listbox.delete(0, AtEnd())
|
||||
exactmatch = 0
|
||||
for item in ok:
|
||||
if item == key: exactmatch = 1
|
||||
self.listbox.insert(AtEnd(), item)
|
||||
if exactmatch:
|
||||
return key
|
||||
n = self.listbox.size()
|
||||
if n == 1:
|
||||
return self.listbox.get(0)
|
||||
# Else return None, meaning not a unique selection
|
||||
|
||||
def update(self):
|
||||
name = self.updatelist()
|
||||
if name:
|
||||
self.show_page(name)
|
||||
self.entry.delete(0, AtEnd())
|
||||
self.updatelist()
|
||||
|
||||
def show_page(self, name):
|
||||
file = '%s/%s.?' % (self.chaptervar.get(), name)
|
||||
fp = os.popen('nroff -man %s | ul -i' % file, 'r')
|
||||
self.text.kill()
|
||||
self.title['text'] = name
|
||||
self.text.parsefile(fp)
|
||||
|
||||
def search_string(self, search):
|
||||
if not search:
|
||||
self.frame.bell()
|
||||
print 'Empty search string'
|
||||
return
|
||||
if not self.casevar.get():
|
||||
map = re.IGNORECASE
|
||||
else:
|
||||
map = None
|
||||
try:
|
||||
if map:
|
||||
prog = re.compile(search, map)
|
||||
else:
|
||||
prog = re.compile(search)
|
||||
except re.error, msg:
|
||||
self.frame.bell()
|
||||
print 'Regex error:', msg
|
||||
return
|
||||
here = self.text.index(AtInsert())
|
||||
lineno = string.atoi(here[:string.find(here, '.')])
|
||||
end = self.text.index(AtEnd())
|
||||
endlineno = string.atoi(end[:string.find(end, '.')])
|
||||
wraplineno = lineno
|
||||
found = 0
|
||||
while 1:
|
||||
lineno = lineno + 1
|
||||
if lineno > endlineno:
|
||||
if wraplineno <= 0:
|
||||
break
|
||||
endlineno = wraplineno
|
||||
lineno = 0
|
||||
wraplineno = 0
|
||||
line = self.text.get('%d.0 linestart' % lineno,
|
||||
'%d.0 lineend' % lineno)
|
||||
i = prog.search(line)
|
||||
if i >= 0:
|
||||
found = 1
|
||||
n = max(1, len(prog.group(0)))
|
||||
try:
|
||||
self.text.tag_remove('sel',
|
||||
AtSelFirst(),
|
||||
AtSelLast())
|
||||
except TclError:
|
||||
pass
|
||||
self.text.tag_add('sel',
|
||||
'%d.%d' % (lineno, i),
|
||||
'%d.%d' % (lineno, i+n))
|
||||
self.text.mark_set(AtInsert(),
|
||||
'%d.%d' % (lineno, i))
|
||||
self.text.yview_pickplace(AtInsert())
|
||||
break
|
||||
if not found:
|
||||
self.frame.bell()
|
||||
|
||||
def main():
|
||||
root = Tk()
|
||||
sb = SelectionBox(root)
|
||||
if sys.argv[1:]:
|
||||
sb.show_page(sys.argv[1])
|
||||
root.minsize(1, 1)
|
||||
root.mainloop()
|
||||
|
||||
main()
|
||||
27
Demo/tkinter/guido/wish.py
Normal file
27
Demo/tkinter/guido/wish.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# This is about all it requires to write a wish shell in Python!
|
||||
|
||||
import _tkinter
|
||||
import os
|
||||
|
||||
tk = _tkinter.create(os.environ['DISPLAY'], 'wish', 'Tk', 1)
|
||||
tk.call('update')
|
||||
|
||||
cmd = ''
|
||||
|
||||
while 1:
|
||||
if cmd: prompt = ''
|
||||
else: prompt = '% '
|
||||
try:
|
||||
line = raw_input(prompt)
|
||||
except EOFError:
|
||||
break
|
||||
cmd = cmd + (line + '\n')
|
||||
if tk.getboolean(tk.call('info', 'complete', cmd)):
|
||||
tk.record(line)
|
||||
try:
|
||||
result = tk.call('eval', cmd)
|
||||
except _tkinter.TclError, msg:
|
||||
print 'TclError:', msg
|
||||
else:
|
||||
if result: print result
|
||||
cmd = ''
|
||||
27
Demo/tkinter/matt/00-HELLO-WORLD.py
Normal file
27
Demo/tkinter/matt/00-HELLO-WORLD.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from Tkinter import *
|
||||
|
||||
# note that there is no explicit call to start Tk.
|
||||
# Tkinter is smart enough to start the system if it's not already going.
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
# a hello button
|
||||
self.hi_there = Button(self, text='Hello',
|
||||
command=self.printit)
|
||||
self.hi_there.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
30
Demo/tkinter/matt/README
Normal file
30
Demo/tkinter/matt/README
Normal file
@@ -0,0 +1,30 @@
|
||||
This directory contains some ad-hoc examples of Tkinter widget
|
||||
creation. The files named
|
||||
|
||||
*-simple.py
|
||||
|
||||
are the ones to start with if you're looking for a bare-bones usage of
|
||||
a widget. The other files are meant to show common usage patters that
|
||||
are a tad more involved.
|
||||
|
||||
If you have a suggestion for an example program, please send mail to
|
||||
|
||||
conway@virginia.edu
|
||||
|
||||
and I'll include it.
|
||||
|
||||
|
||||
matt
|
||||
|
||||
TODO
|
||||
-------
|
||||
The X selection
|
||||
Dialog Boxes
|
||||
More canvas examples
|
||||
Message widgets
|
||||
Text Editors
|
||||
Scrollbars
|
||||
Listboxes
|
||||
|
||||
|
||||
|
||||
35
Demo/tkinter/matt/animation-simple.py
Normal file
35
Demo/tkinter/matt/animation-simple.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from Tkinter import *
|
||||
|
||||
# This program shows how to use the "after" function to make animation.
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
self.draw = Canvas(self, width="5i", height="5i")
|
||||
|
||||
# all of these work..
|
||||
self.draw.create_rectangle(0, 0, 10, 10, tags="thing", fill="blue")
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
def moveThing(self, *args):
|
||||
# move 1/10 of an inch every 1/10 sec (1" per second, smoothly)
|
||||
self.draw.move("thing", "0.01i", "0.01i")
|
||||
self.after(10, self.moveThing)
|
||||
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
self.after(10, self.moveThing)
|
||||
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
44
Demo/tkinter/matt/animation-w-velocity-ctrl.py
Normal file
44
Demo/tkinter/matt/animation-w-velocity-ctrl.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from Tkinter import *
|
||||
|
||||
# this is the same as simple-demo-1.py, but uses
|
||||
# subclassing.
|
||||
# note that there is no explicit call to start Tk.
|
||||
# Tkinter is smart enough to start the system if it's not already going.
|
||||
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
|
||||
self.draw = Canvas(self, width="5i", height="5i")
|
||||
|
||||
self.speed = Scale(self, orient=HORIZONTAL, from_=-100, to=100)
|
||||
|
||||
self.speed.pack(side=BOTTOM, fill=X)
|
||||
|
||||
# all of these work..
|
||||
self.draw.create_rectangle(0, 0, 10, 10, tags="thing", fill="blue")
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
def moveThing(self, *args):
|
||||
velocity = self.speed.get()
|
||||
str = float(velocity) / 1000.0
|
||||
str = "%ri" % (str,)
|
||||
self.draw.move("thing", str, str)
|
||||
self.after(10, self.moveThing)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
self.after(10, self.moveThing)
|
||||
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
44
Demo/tkinter/matt/bind-w-mult-calls-p-type.py
Normal file
44
Demo/tkinter/matt/bind-w-mult-calls-p-type.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from Tkinter import *
|
||||
import string
|
||||
|
||||
# This program shows how to use a simple type-in box
|
||||
|
||||
class App(Frame):
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
self.pack()
|
||||
|
||||
self.entrythingy = Entry()
|
||||
self.entrythingy.pack()
|
||||
|
||||
# and here we get a callback when the user hits return. we could
|
||||
# make the key that triggers the callback anything we wanted to.
|
||||
# other typical options might be <Key-Tab> or <Key> (for anything)
|
||||
self.entrythingy.bind('<Key-Return>', self.print_contents)
|
||||
|
||||
# Note that here is where we bind a completely different callback to
|
||||
# the same event. We pass "+" here to indicate that we wish to ADD
|
||||
# this callback to the list associated with this event type.
|
||||
# Not specifying "+" would simply override whatever callback was
|
||||
# defined on this event.
|
||||
self.entrythingy.bind('<Key-Return>', self.print_something_else, "+")
|
||||
|
||||
def print_contents(self, event):
|
||||
print "hi. contents of entry is now ---->", self.entrythingy.get()
|
||||
|
||||
|
||||
def print_something_else(self, event):
|
||||
print "hi. Now doing something completely different"
|
||||
|
||||
|
||||
root = App()
|
||||
root.master.title("Foo")
|
||||
root.mainloop()
|
||||
|
||||
|
||||
|
||||
# secret tip for experts: if you pass *any* non-false value as
|
||||
# the third parameter to bind(), Tkinter.py will accumulate
|
||||
# callbacks instead of overwriting. I use "+" here because that's
|
||||
# the Tk notation for getting this sort of behavior. The perfect GUI
|
||||
# interface would use a less obscure notation.
|
||||
28
Demo/tkinter/matt/canvas-demo-simple.py
Normal file
28
Demo/tkinter/matt/canvas-demo-simple.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from Tkinter import *
|
||||
|
||||
# this program creates a canvas and puts a single polygon on the canvas
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
|
||||
self.draw = Canvas(self, width="5i", height="5i")
|
||||
|
||||
# see the other demos for other ways of specifying coords for a polygon
|
||||
self.draw.create_rectangle(0, 0, "3i", "3i", fill="black")
|
||||
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
61
Demo/tkinter/matt/canvas-gridding.py
Normal file
61
Demo/tkinter/matt/canvas-gridding.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from Tkinter import *
|
||||
|
||||
# this is the same as simple-demo-1.py, but uses
|
||||
# subclassing.
|
||||
# note that there is no explicit call to start Tk.
|
||||
# Tkinter is smart enough to start the system if it's not already going.
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT',
|
||||
background='red',
|
||||
foreground='white',
|
||||
height=3,
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
|
||||
self.canvasObject = Canvas(self, width="5i", height="5i")
|
||||
self.canvasObject.pack(side=LEFT)
|
||||
|
||||
def mouseDown(self, event):
|
||||
# canvas x and y take the screen coords from the event and translate
|
||||
# them into the coordinate system of the canvas object
|
||||
self.startx = self.canvasObject.canvasx(event.x, self.griddingSize)
|
||||
self.starty = self.canvasObject.canvasy(event.y, self.griddingSize)
|
||||
|
||||
def mouseMotion(self, event):
|
||||
# canvas x and y take the screen coords from the event and translate
|
||||
# them into the coordinate system of the canvas object
|
||||
x = self.canvasObject.canvasx(event.x, self.griddingSize)
|
||||
y = self.canvasObject.canvasy(event.y, self.griddingSize)
|
||||
|
||||
if (self.startx != event.x) and (self.starty != event.y) :
|
||||
self.canvasObject.delete(self.rubberbandBox)
|
||||
self.rubberbandBox = self.canvasObject.create_rectangle(
|
||||
self.startx, self.starty, x, y)
|
||||
# this flushes the output, making sure that
|
||||
# the rectangle makes it to the screen
|
||||
# before the next event is handled
|
||||
self.update_idletasks()
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
# this is a "tagOrId" for the rectangle we draw on the canvas
|
||||
self.rubberbandBox = None
|
||||
|
||||
# this is the size of the gridding squares
|
||||
self.griddingSize = 50
|
||||
|
||||
Widget.bind(self.canvasObject, "<Button-1>", self.mouseDown)
|
||||
Widget.bind(self.canvasObject, "<Button1-Motion>", self.mouseMotion)
|
||||
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
62
Demo/tkinter/matt/canvas-moving-or-creating.py
Normal file
62
Demo/tkinter/matt/canvas-moving-or-creating.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from Tkinter import *
|
||||
|
||||
# this file demonstrates a more sophisticated movement --
|
||||
# move dots or create new ones if you click outside the dots
|
||||
|
||||
class Test(Frame):
|
||||
###################################################################
|
||||
###### Event callbacks for THE CANVAS (not the stuff drawn on it)
|
||||
###################################################################
|
||||
def mouseDown(self, event):
|
||||
# see if we're inside a dot. If we are, it
|
||||
# gets tagged as CURRENT for free by tk.
|
||||
if not event.widget.find_withtag(CURRENT):
|
||||
# there is no dot here, so we can make one,
|
||||
# and bind some interesting behavior to it.
|
||||
# ------
|
||||
# create a dot, and mark it as CURRENT
|
||||
fred = self.draw.create_oval(
|
||||
event.x - 10, event.y -10, event.x +10, event.y + 10,
|
||||
fill="green", tags=CURRENT)
|
||||
|
||||
self.draw.tag_bind(fred, "<Any-Enter>", self.mouseEnter)
|
||||
self.draw.tag_bind(fred, "<Any-Leave>", self.mouseLeave)
|
||||
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
def mouseMove(self, event):
|
||||
self.draw.move(CURRENT, event.x - self.lastx, event.y - self.lasty)
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
###################################################################
|
||||
###### Event callbacks for canvas ITEMS (stuff drawn on the canvas)
|
||||
###################################################################
|
||||
def mouseEnter(self, event):
|
||||
# the CURRENT tag is applied to the object the cursor is over.
|
||||
# this happens automatically.
|
||||
self.draw.itemconfig(CURRENT, fill="red")
|
||||
|
||||
def mouseLeave(self, event):
|
||||
# the CURRENT tag is applied to the object the cursor is over.
|
||||
# this happens automatically.
|
||||
self.draw.itemconfig(CURRENT, fill="blue")
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
self.draw = Canvas(self, width="5i", height="5i")
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
Widget.bind(self.draw, "<1>", self.mouseDown)
|
||||
Widget.bind(self.draw, "<B1-Motion>", self.mouseMove)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
55
Demo/tkinter/matt/canvas-moving-w-mouse.py
Normal file
55
Demo/tkinter/matt/canvas-moving-w-mouse.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from Tkinter import *
|
||||
|
||||
# this file demonstrates the movement of a single canvas item under mouse control
|
||||
|
||||
class Test(Frame):
|
||||
###################################################################
|
||||
###### Event callbacks for THE CANVAS (not the stuff drawn on it)
|
||||
###################################################################
|
||||
def mouseDown(self, event):
|
||||
# remember where the mouse went down
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
def mouseMove(self, event):
|
||||
# whatever the mouse is over gets tagged as CURRENT for free by tk.
|
||||
self.draw.move(CURRENT, event.x - self.lastx, event.y - self.lasty)
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
###################################################################
|
||||
###### Event callbacks for canvas ITEMS (stuff drawn on the canvas)
|
||||
###################################################################
|
||||
def mouseEnter(self, event):
|
||||
# the CURRENT tag is applied to the object the cursor is over.
|
||||
# this happens automatically.
|
||||
self.draw.itemconfig(CURRENT, fill="red")
|
||||
|
||||
def mouseLeave(self, event):
|
||||
# the CURRENT tag is applied to the object the cursor is over.
|
||||
# this happens automatically.
|
||||
self.draw.itemconfig(CURRENT, fill="blue")
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
self.draw = Canvas(self, width="5i", height="5i")
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
fred = self.draw.create_oval(0, 0, 20, 20,
|
||||
fill="green", tags="selected")
|
||||
|
||||
self.draw.tag_bind(fred, "<Any-Enter>", self.mouseEnter)
|
||||
self.draw.tag_bind(fred, "<Any-Leave>", self.mouseLeave)
|
||||
|
||||
Widget.bind(self.draw, "<1>", self.mouseDown)
|
||||
Widget.bind(self.draw, "<B1-Motion>", self.mouseMove)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
78
Demo/tkinter/matt/canvas-mult-item-sel.py
Normal file
78
Demo/tkinter/matt/canvas-mult-item-sel.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from Tkinter import *
|
||||
|
||||
# allows moving dots with multiple selection.
|
||||
|
||||
SELECTED_COLOR = "red"
|
||||
UNSELECTED_COLOR = "blue"
|
||||
|
||||
class Test(Frame):
|
||||
###################################################################
|
||||
###### Event callbacks for THE CANVAS (not the stuff drawn on it)
|
||||
###################################################################
|
||||
def mouseDown(self, event):
|
||||
# see if we're inside a dot. If we are, it
|
||||
# gets tagged as CURRENT for free by tk.
|
||||
|
||||
if not event.widget.find_withtag(CURRENT):
|
||||
# we clicked outside of all dots on the canvas. unselect all.
|
||||
|
||||
# re-color everything back to an unselected color
|
||||
self.draw.itemconfig("selected", fill=UNSELECTED_COLOR)
|
||||
# unselect everything
|
||||
self.draw.dtag("selected")
|
||||
else:
|
||||
# mark as "selected" the thing the cursor is under
|
||||
self.draw.addtag("selected", "withtag", CURRENT)
|
||||
# color it as selected
|
||||
self.draw.itemconfig("selected", fill=SELECTED_COLOR)
|
||||
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
|
||||
def mouseMove(self, event):
|
||||
self.draw.move("selected", event.x - self.lastx, event.y - self.lasty)
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
def makeNewDot(self):
|
||||
# create a dot, and mark it as current
|
||||
fred = self.draw.create_oval(0, 0, 20, 20,
|
||||
fill=SELECTED_COLOR, tags=CURRENT)
|
||||
# and make it selected
|
||||
self.draw.addtag("selected", "withtag", CURRENT)
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
|
||||
################
|
||||
# make the canvas and bind some behavior to it
|
||||
################
|
||||
self.draw = Canvas(self, width="5i", height="5i")
|
||||
Widget.bind(self.draw, "<1>", self.mouseDown)
|
||||
Widget.bind(self.draw, "<B1-Motion>", self.mouseMove)
|
||||
|
||||
# and other things.....
|
||||
self.button = Button(self, text="make a new dot", foreground="blue",
|
||||
command=self.makeNewDot)
|
||||
|
||||
message = ("%s dots are selected and can be dragged.\n"
|
||||
"%s are not selected.\n"
|
||||
"Click in a dot to select it.\n"
|
||||
"Click on empty space to deselect all dots."
|
||||
) % (SELECTED_COLOR, UNSELECTED_COLOR)
|
||||
self.label = Message(self, width="5i", text=message)
|
||||
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
self.label.pack(side=BOTTOM, fill=X, expand=1)
|
||||
self.button.pack(side=BOTTOM, fill=X)
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
49
Demo/tkinter/matt/canvas-reading-tag-info.py
Normal file
49
Demo/tkinter/matt/canvas-reading-tag-info.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from Tkinter import *
|
||||
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
|
||||
self.drawing = Canvas(self, width="5i", height="5i")
|
||||
|
||||
# make a shape
|
||||
pgon = self.drawing.create_polygon(
|
||||
10, 10, 110, 10, 110, 110, 10 , 110,
|
||||
fill="red", tags=("weee", "foo", "groo"))
|
||||
|
||||
# this is how you query an object for its attributes
|
||||
# config options FOR CANVAS ITEMS always come back in tuples of length 5.
|
||||
# 0 attribute name
|
||||
# 1 BLANK
|
||||
# 2 BLANK
|
||||
# 3 default value
|
||||
# 4 current value
|
||||
# the blank spots are for consistency with the config command that
|
||||
# is used for widgets. (remember, this is for ITEMS drawn
|
||||
# on a canvas widget, not widgets)
|
||||
option_value = self.drawing.itemconfig(pgon, "stipple")
|
||||
print "pgon's current stipple value is -->", option_value[4], "<--"
|
||||
option_value = self.drawing.itemconfig(pgon, "fill")
|
||||
print "pgon's current fill value is -->", option_value[4], "<--"
|
||||
print " when he is usually colored -->", option_value[3], "<--"
|
||||
|
||||
## here we print out all the tags associated with this object
|
||||
option_value = self.drawing.itemconfig(pgon, "tags")
|
||||
print "pgon's tags are", option_value[4]
|
||||
|
||||
self.drawing.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
36
Demo/tkinter/matt/canvas-w-widget-draw-el.py
Normal file
36
Demo/tkinter/matt/canvas-w-widget-draw-el.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from Tkinter import *
|
||||
|
||||
# this file demonstrates the creation of widgets as part of a canvas object
|
||||
|
||||
class Test(Frame):
|
||||
def printhi(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
|
||||
self.draw = Canvas(self, width="5i", height="5i")
|
||||
|
||||
self.button = Button(self, text="this is a button",
|
||||
command=self.printhi)
|
||||
|
||||
# note here the coords are given in pixels (form the
|
||||
# upper right and corner of the window, as usual for X)
|
||||
# but might just have well been given in inches or points or
|
||||
# whatever...use the "anchor" option to control what point of the
|
||||
# widget (in this case the button) gets mapped to the given x, y.
|
||||
# you can specify corners, edges, center, etc...
|
||||
self.draw.create_window(300, 300, window=self.button)
|
||||
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
60
Demo/tkinter/matt/canvas-with-scrollbars.py
Normal file
60
Demo/tkinter/matt/canvas-with-scrollbars.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from Tkinter import *
|
||||
|
||||
# This example program creates a scrolling canvas, and demonstrates
|
||||
# how to tie scrollbars and canvases together. The mechanism
|
||||
# is analogus for listboxes and other widgets with
|
||||
# "xscroll" and "yscroll" configuration options.
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.question = Label(self, text="Can Find The BLUE Square??????")
|
||||
self.question.pack()
|
||||
|
||||
self.QUIT = Button(self, text='QUIT', background='red',
|
||||
height=3, command=self.quit)
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
spacer = Frame(self, height="0.25i")
|
||||
spacer.pack(side=BOTTOM)
|
||||
|
||||
# notice that the scroll region (20" x 20") is larger than
|
||||
# displayed size of the widget (5" x 5")
|
||||
self.draw = Canvas(self, width="5i", height="5i",
|
||||
background="white",
|
||||
scrollregion=(0, 0, "20i", "20i"))
|
||||
|
||||
self.draw.scrollX = Scrollbar(self, orient=HORIZONTAL)
|
||||
self.draw.scrollY = Scrollbar(self, orient=VERTICAL)
|
||||
|
||||
# now tie the three together. This is standard boilerplate text
|
||||
self.draw['xscrollcommand'] = self.draw.scrollX.set
|
||||
self.draw['yscrollcommand'] = self.draw.scrollY.set
|
||||
self.draw.scrollX['command'] = self.draw.xview
|
||||
self.draw.scrollY['command'] = self.draw.yview
|
||||
|
||||
# draw something. Note that the first square
|
||||
# is visible, but you need to scroll to see the second one.
|
||||
self.draw.create_rectangle(0, 0, "3.5i", "3.5i", fill="black")
|
||||
self.draw.create_rectangle("10i", "10i", "13.5i", "13.5i", fill="blue")
|
||||
|
||||
# pack 'em up
|
||||
self.draw.scrollX.pack(side=BOTTOM, fill=X)
|
||||
self.draw.scrollY.pack(side=RIGHT, fill=Y)
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
|
||||
def scrollCanvasX(self, *args):
|
||||
print "scrolling", args
|
||||
print self.draw.scrollX.get()
|
||||
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
64
Demo/tkinter/matt/dialog-box.py
Normal file
64
Demo/tkinter/matt/dialog-box.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from Tkinter import *
|
||||
from Dialog import Dialog
|
||||
|
||||
# this shows how to create a new window with a button in it
|
||||
# that can create new windows
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def makeWindow(self):
|
||||
"""Create a top-level dialog with some buttons.
|
||||
|
||||
This uses the Dialog class, which is a wrapper around the Tcl/Tk
|
||||
tk_dialog script. The function returns 0 if the user clicks 'yes'
|
||||
or 1 if the user clicks 'no'.
|
||||
"""
|
||||
# the parameters to this call are as follows:
|
||||
d = Dialog(
|
||||
self, ## name of a toplevel window
|
||||
title="fred the dialog box",## title on the window
|
||||
text="click on a choice", ## message to appear in window
|
||||
bitmap="info", ## bitmap (if any) to appear;
|
||||
## if none, use ""
|
||||
# legal values here are:
|
||||
# string what it looks like
|
||||
# ----------------------------------------------
|
||||
# error a circle with a slash through it
|
||||
# grey25 grey square
|
||||
# grey50 darker grey square
|
||||
# hourglass use for "wait.."
|
||||
# info a large, lower case "i"
|
||||
# questhead a human head with a "?" in it
|
||||
# question a large "?"
|
||||
# warning a large "!"
|
||||
# @fname X bitmap where fname is the path to the file
|
||||
#
|
||||
default=0, # the index of the default button choice.
|
||||
# hitting return selects this
|
||||
strings=("yes", "no"))
|
||||
# values of the 'strings' key are the labels for the
|
||||
# buttons that appear left to right in the dialog box
|
||||
return d.num
|
||||
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
# a hello button
|
||||
self.hi_there = Button(self, text='Make a New Window',
|
||||
command=self.makeWindow)
|
||||
self.hi_there.pack(side=LEFT)
|
||||
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.windownum = 0
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
24
Demo/tkinter/matt/entry-simple.py
Normal file
24
Demo/tkinter/matt/entry-simple.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from Tkinter import *
|
||||
import string
|
||||
|
||||
# This program shows how to use a simple type-in box
|
||||
|
||||
class App(Frame):
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
self.pack()
|
||||
|
||||
self.entrythingy = Entry()
|
||||
self.entrythingy.pack()
|
||||
|
||||
# and here we get a callback when the user hits return. we could
|
||||
# make the key that triggers the callback anything we wanted to.
|
||||
# other typical options might be <Key-Tab> or <Key> (for anything)
|
||||
self.entrythingy.bind('<Key-Return>', self.print_contents)
|
||||
|
||||
def print_contents(self, event):
|
||||
print "hi. contents of entry is now ---->", self.entrythingy.get()
|
||||
|
||||
root = App()
|
||||
root.master.title("Foo")
|
||||
root.mainloop()
|
||||
46
Demo/tkinter/matt/entry-with-shared-variable.py
Normal file
46
Demo/tkinter/matt/entry-with-shared-variable.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from Tkinter import *
|
||||
import string
|
||||
|
||||
# This program shows how to make a typein box shadow a program variable.
|
||||
|
||||
class App(Frame):
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
self.pack()
|
||||
|
||||
self.entrythingy = Entry(self)
|
||||
self.entrythingy.pack()
|
||||
|
||||
self.button = Button(self, text="Uppercase The Entry",
|
||||
command=self.upper)
|
||||
self.button.pack()
|
||||
|
||||
# here we have the text in the entry widget tied to a variable.
|
||||
# changes in the variable are echoed in the widget and vice versa.
|
||||
# Very handy.
|
||||
# there are other Variable types. See Tkinter.py for all
|
||||
# the other variable types that can be shadowed
|
||||
self.contents = StringVar()
|
||||
self.contents.set("this is a variable")
|
||||
self.entrythingy.config(textvariable=self.contents)
|
||||
|
||||
# and here we get a callback when the user hits return. we could
|
||||
# make the key that triggers the callback anything we wanted to.
|
||||
# other typical options might be <Key-Tab> or <Key> (for anything)
|
||||
self.entrythingy.bind('<Key-Return>', self.print_contents)
|
||||
|
||||
def upper(self):
|
||||
# notice here, we don't actually refer to the entry box.
|
||||
# we just operate on the string variable and we
|
||||
# because it's being looked at by the entry widget, changing
|
||||
# the variable changes the entry widget display automatically.
|
||||
# the strange get/set operators are clunky, true...
|
||||
str = string.upper(self.contents.get())
|
||||
self.contents.set(str)
|
||||
|
||||
def print_contents(self, event):
|
||||
print "hi. contents of entry is now ---->", self.contents.get()
|
||||
|
||||
root = App()
|
||||
root.master.title("Foo")
|
||||
root.mainloop()
|
||||
42
Demo/tkinter/matt/killing-window-w-wm.py
Normal file
42
Demo/tkinter/matt/killing-window-w-wm.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from Tkinter import *
|
||||
|
||||
# This file shows how to trap the killing of a window
|
||||
# when the user uses window manager menus (typ. upper left hand corner
|
||||
# menu in the decoration border).
|
||||
|
||||
|
||||
### ******* this isn't really called -- read the comments
|
||||
def my_delete_callback():
|
||||
print "whoops -- tried to delete me!"
|
||||
|
||||
class Test(Frame):
|
||||
def deathHandler(self, event):
|
||||
print self, "is now getting nuked. performing some save here...."
|
||||
|
||||
def createWidgets(self):
|
||||
# a hello button
|
||||
self.hi_there = Button(self, text='Hello')
|
||||
self.hi_there.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
###
|
||||
### PREVENT WM kills from happening
|
||||
###
|
||||
|
||||
# the docs would have you do this:
|
||||
|
||||
# self.master.protocol("WM_DELETE_WINDOW", my_delete_callback)
|
||||
|
||||
# unfortunately, some window managers will not send this request to a window.
|
||||
# the "protocol" function seems incapable of trapping these "aggressive" window kills.
|
||||
# this line of code catches everything, tho. The window is deleted, but you have a chance
|
||||
# of cleaning up first.
|
||||
self.bind_all("<Destroy>", self.deathHandler)
|
||||
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
244
Demo/tkinter/matt/menu-all-types-of-entries.py
Normal file
244
Demo/tkinter/matt/menu-all-types-of-entries.py
Normal file
@@ -0,0 +1,244 @@
|
||||
from Tkinter import *
|
||||
|
||||
# some vocabulary to keep from getting confused. This terminology
|
||||
# is something I cooked up for this file, but follows the man pages
|
||||
# pretty closely
|
||||
#
|
||||
#
|
||||
#
|
||||
# This is a MENUBUTTON
|
||||
# V
|
||||
# +-------------+
|
||||
# | |
|
||||
#
|
||||
# +------------++------------++------------+
|
||||
# | || || |
|
||||
# | File || Edit || Options | <-------- the MENUBAR
|
||||
# | || || |
|
||||
# +------------++------------++------------+
|
||||
# | New... |
|
||||
# | Open... |
|
||||
# | Print |
|
||||
# | | <-------- This is a MENU. The lines of text in the menu are
|
||||
# | | MENU ENTRIES
|
||||
# | +---------------+
|
||||
# | Open Files > | file1 |
|
||||
# | | file2 |
|
||||
# | | another file | <------ this cascading part is also a MENU
|
||||
# +----------------| |
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# +---------------+
|
||||
|
||||
|
||||
|
||||
# some miscellaneous callbacks
|
||||
def new_file():
|
||||
print "opening new file"
|
||||
|
||||
def open_file():
|
||||
print "opening OLD file"
|
||||
|
||||
def print_something():
|
||||
print "picked a menu item"
|
||||
|
||||
|
||||
|
||||
anchovies = 0
|
||||
|
||||
def print_anchovies():
|
||||
global anchovies
|
||||
anchovies = not anchovies
|
||||
print "anchovies?", anchovies
|
||||
|
||||
def makeCommandMenu():
|
||||
# make menu button
|
||||
Command_button = Menubutton(mBar, text='Simple Button Commands',
|
||||
underline=0)
|
||||
Command_button.pack(side=LEFT, padx="2m")
|
||||
|
||||
# make the pulldown part of the File menu. The parameter passed is the master.
|
||||
# we attach it to the button as a python attribute called "menu" by convention.
|
||||
# hopefully this isn't too confusing...
|
||||
Command_button.menu = Menu(Command_button)
|
||||
|
||||
# just to be cute, let's disable the undo option:
|
||||
Command_button.menu.add_command(label="Undo")
|
||||
# undo is the 0th entry...
|
||||
Command_button.menu.entryconfig(0, state=DISABLED)
|
||||
|
||||
Command_button.menu.add_command(label='New...', underline=0,
|
||||
command=new_file)
|
||||
Command_button.menu.add_command(label='Open...', underline=0,
|
||||
command=open_file)
|
||||
Command_button.menu.add_command(label='Different Font', underline=0,
|
||||
font='-*-helvetica-*-r-*-*-*-180-*-*-*-*-*-*',
|
||||
command=print_something)
|
||||
|
||||
# we can make bitmaps be menu entries too. File format is X11 bitmap.
|
||||
# if you use XV, save it under X11 bitmap format. duh-uh.,..
|
||||
Command_button.menu.add_command(
|
||||
bitmap="info")
|
||||
#bitmap='@/home/mjc4y/dilbert/project.status.is.doomed.last.panel.bm')
|
||||
|
||||
# this is just a line
|
||||
Command_button.menu.add('separator')
|
||||
|
||||
# change the color
|
||||
Command_button.menu.add_command(label='Quit', underline=0,
|
||||
background='red',
|
||||
activebackground='green',
|
||||
command=Command_button.quit)
|
||||
|
||||
# set up a pointer from the file menubutton back to the file menu
|
||||
Command_button['menu'] = Command_button.menu
|
||||
|
||||
return Command_button
|
||||
|
||||
|
||||
|
||||
def makeCascadeMenu():
|
||||
# make menu button
|
||||
Cascade_button = Menubutton(mBar, text='Cascading Menus', underline=0)
|
||||
Cascade_button.pack(side=LEFT, padx="2m")
|
||||
|
||||
# the primary pulldown
|
||||
Cascade_button.menu = Menu(Cascade_button)
|
||||
|
||||
# this is the menu that cascades from the primary pulldown....
|
||||
Cascade_button.menu.choices = Menu(Cascade_button.menu)
|
||||
|
||||
# ...and this is a menu that cascades from that.
|
||||
Cascade_button.menu.choices.weirdones = Menu(Cascade_button.menu.choices)
|
||||
|
||||
# then you define the menus from the deepest level on up.
|
||||
Cascade_button.menu.choices.weirdones.add_command(label='avacado')
|
||||
Cascade_button.menu.choices.weirdones.add_command(label='belgian endive')
|
||||
Cascade_button.menu.choices.weirdones.add_command(label='beefaroni')
|
||||
|
||||
# definition of the menu one level up...
|
||||
Cascade_button.menu.choices.add_command(label='Chocolate')
|
||||
Cascade_button.menu.choices.add_command(label='Vanilla')
|
||||
Cascade_button.menu.choices.add_command(label='TuttiFruiti')
|
||||
Cascade_button.menu.choices.add_command(label='WopBopaLoopBapABopBamBoom')
|
||||
Cascade_button.menu.choices.add_command(label='Rocky Road')
|
||||
Cascade_button.menu.choices.add_command(label='BubbleGum')
|
||||
Cascade_button.menu.choices.add_cascade(
|
||||
label='Weird Flavors',
|
||||
menu=Cascade_button.menu.choices.weirdones)
|
||||
|
||||
# and finally, the definition for the top level
|
||||
Cascade_button.menu.add_cascade(label='more choices',
|
||||
menu=Cascade_button.menu.choices)
|
||||
|
||||
Cascade_button['menu'] = Cascade_button.menu
|
||||
|
||||
return Cascade_button
|
||||
|
||||
def makeCheckbuttonMenu():
|
||||
global fred
|
||||
# make menu button
|
||||
Checkbutton_button = Menubutton(mBar, text='Checkbutton Menus',
|
||||
underline=0)
|
||||
Checkbutton_button.pack(side=LEFT, padx='2m')
|
||||
|
||||
# the primary pulldown
|
||||
Checkbutton_button.menu = Menu(Checkbutton_button)
|
||||
|
||||
# and all the check buttons. Note that the "variable" "onvalue" and "offvalue" options
|
||||
# are not supported correctly at present. You have to do all your application
|
||||
# work through the calback.
|
||||
Checkbutton_button.menu.add_checkbutton(label='Pepperoni')
|
||||
Checkbutton_button.menu.add_checkbutton(label='Sausage')
|
||||
Checkbutton_button.menu.add_checkbutton(label='Extra Cheese')
|
||||
|
||||
# so here's a callback
|
||||
Checkbutton_button.menu.add_checkbutton(label='Anchovy',
|
||||
command=print_anchovies)
|
||||
|
||||
# and start with anchovies selected to be on. Do this by
|
||||
# calling invoke on this menu option. To refer to the "anchovy" menu
|
||||
# entry we need to know it's index. To do this, we use the index method
|
||||
# which takes arguments of several forms:
|
||||
#
|
||||
# argument what it does
|
||||
# -----------------------------------
|
||||
# a number -- this is useless.
|
||||
# "last" -- last option in the menu
|
||||
# "none" -- used with the activate command. see the man page on menus
|
||||
# "active" -- the currently active menu option. A menu option is made active
|
||||
# with the 'activate' method
|
||||
# "@number" -- where 'number' is an integer and is treated like a y coordinate in pixels
|
||||
# string pattern -- this is the option used below, and attempts to match "labels" using the
|
||||
# rules of Tcl_StringMatch
|
||||
Checkbutton_button.menu.invoke(Checkbutton_button.menu.index('Anchovy'))
|
||||
|
||||
# set up a pointer from the file menubutton back to the file menu
|
||||
Checkbutton_button['menu'] = Checkbutton_button.menu
|
||||
|
||||
return Checkbutton_button
|
||||
|
||||
|
||||
def makeRadiobuttonMenu():
|
||||
# make menu button
|
||||
Radiobutton_button = Menubutton(mBar, text='Radiobutton Menus',
|
||||
underline=0)
|
||||
Radiobutton_button.pack(side=LEFT, padx='2m')
|
||||
|
||||
# the primary pulldown
|
||||
Radiobutton_button.menu = Menu(Radiobutton_button)
|
||||
|
||||
# and all the Radio buttons. Note that the "variable" "onvalue" and "offvalue" options
|
||||
# are not supported correctly at present. You have to do all your application
|
||||
# work through the calback.
|
||||
Radiobutton_button.menu.add_radiobutton(label='Republican')
|
||||
Radiobutton_button.menu.add_radiobutton(label='Democrat')
|
||||
Radiobutton_button.menu.add_radiobutton(label='Libertarian')
|
||||
Radiobutton_button.menu.add_radiobutton(label='Commie')
|
||||
Radiobutton_button.menu.add_radiobutton(label='Facist')
|
||||
Radiobutton_button.menu.add_radiobutton(label='Labor Party')
|
||||
Radiobutton_button.menu.add_radiobutton(label='Torie')
|
||||
Radiobutton_button.menu.add_radiobutton(label='Independent')
|
||||
Radiobutton_button.menu.add_radiobutton(label='Anarchist')
|
||||
Radiobutton_button.menu.add_radiobutton(label='No Opinion')
|
||||
|
||||
# set up a pointer from the file menubutton back to the file menu
|
||||
Radiobutton_button['menu'] = Radiobutton_button.menu
|
||||
|
||||
return Radiobutton_button
|
||||
|
||||
|
||||
def makeDisabledMenu():
|
||||
Dummy_button = Menubutton(mBar, text='Dead Menu', underline=0)
|
||||
Dummy_button.pack(side=LEFT, padx='2m')
|
||||
|
||||
# this is the standard way of turning off a whole menu
|
||||
Dummy_button["state"] = DISABLED
|
||||
return Dummy_button
|
||||
|
||||
|
||||
#################################################
|
||||
#### Main starts here ...
|
||||
root = Tk()
|
||||
|
||||
|
||||
# make a menu bar
|
||||
mBar = Frame(root, relief=RAISED, borderwidth=2)
|
||||
mBar.pack(fill=X)
|
||||
|
||||
Command_button = makeCommandMenu()
|
||||
Cascade_button = makeCascadeMenu()
|
||||
Checkbutton_button = makeCheckbuttonMenu()
|
||||
Radiobutton_button = makeRadiobuttonMenu()
|
||||
NoMenu = makeDisabledMenu()
|
||||
|
||||
# finally, install the buttons in the menu bar.
|
||||
# This allows for scanning from one menubutton to the next.
|
||||
mBar.tk_menuBar(Command_button, Cascade_button, Checkbutton_button, Radiobutton_button, NoMenu)
|
||||
|
||||
|
||||
root.title('menu demo')
|
||||
root.iconname('menu demo')
|
||||
|
||||
root.mainloop()
|
||||
112
Demo/tkinter/matt/menu-simple.py
Normal file
112
Demo/tkinter/matt/menu-simple.py
Normal file
@@ -0,0 +1,112 @@
|
||||
from Tkinter import *
|
||||
|
||||
# some vocabulary to keep from getting confused. This terminology
|
||||
# is something I cooked up for this file, but follows the man pages
|
||||
# pretty closely
|
||||
#
|
||||
#
|
||||
#
|
||||
# This is a MENUBUTTON
|
||||
# V
|
||||
# +-------------+
|
||||
# | |
|
||||
#
|
||||
# +------------++------------++------------+
|
||||
# | || || |
|
||||
# | File || Edit || Options | <-------- the MENUBAR
|
||||
# | || || |
|
||||
# +------------++------------++------------+
|
||||
# | New... |
|
||||
# | Open... |
|
||||
# | Print |
|
||||
# | | <------ This is a MENU. The lines of text in the menu are
|
||||
# | | MENU ENTRIES
|
||||
# | +---------------+
|
||||
# | Open Files > | file1 |
|
||||
# | | file2 |
|
||||
# | | another file | <------ this cascading part is also a MENU
|
||||
# +----------------| |
|
||||
# | |
|
||||
# | |
|
||||
# | |
|
||||
# +---------------+
|
||||
|
||||
|
||||
|
||||
def new_file():
|
||||
print "opening new file"
|
||||
|
||||
|
||||
def open_file():
|
||||
print "opening OLD file"
|
||||
|
||||
|
||||
def makeFileMenu():
|
||||
# make menu button : "File"
|
||||
File_button = Menubutton(mBar, text='File', underline=0)
|
||||
File_button.pack(side=LEFT, padx="1m")
|
||||
File_button.menu = Menu(File_button)
|
||||
|
||||
# add an item. The first param is a menu entry type,
|
||||
# must be one of: "cascade", "checkbutton", "command", "radiobutton", "separator"
|
||||
# see menu-demo-2.py for examples of use
|
||||
File_button.menu.add_command(label='New...', underline=0,
|
||||
command=new_file)
|
||||
|
||||
|
||||
File_button.menu.add_command(label='Open...', underline=0,
|
||||
command=open_file)
|
||||
|
||||
File_button.menu.add_command(label='Quit', underline=0,
|
||||
command='exit')
|
||||
|
||||
# set up a pointer from the file menubutton back to the file menu
|
||||
File_button['menu'] = File_button.menu
|
||||
|
||||
return File_button
|
||||
|
||||
|
||||
|
||||
def makeEditMenu():
|
||||
Edit_button = Menubutton(mBar, text='Edit', underline=0)
|
||||
Edit_button.pack(side=LEFT, padx="1m")
|
||||
Edit_button.menu = Menu(Edit_button)
|
||||
|
||||
# just to be cute, let's disable the undo option:
|
||||
Edit_button.menu.add('command', label="Undo")
|
||||
# Since the tear-off bar is the 0th entry,
|
||||
# undo is the 1st entry...
|
||||
Edit_button.menu.entryconfig(1, state=DISABLED)
|
||||
|
||||
# and these are just for show. No "command" callbacks attached.
|
||||
Edit_button.menu.add_command(label="Cut")
|
||||
Edit_button.menu.add_command(label="Copy")
|
||||
Edit_button.menu.add_command(label="Paste")
|
||||
|
||||
# set up a pointer from the file menubutton back to the file menu
|
||||
Edit_button['menu'] = Edit_button.menu
|
||||
|
||||
return Edit_button
|
||||
|
||||
|
||||
#################################################
|
||||
|
||||
#### Main starts here ...
|
||||
root = Tk()
|
||||
|
||||
|
||||
# make a menu bar
|
||||
mBar = Frame(root, relief=RAISED, borderwidth=2)
|
||||
mBar.pack(fill=X)
|
||||
|
||||
File_button = makeFileMenu()
|
||||
Edit_button = makeEditMenu()
|
||||
|
||||
# finally, install the buttons in the menu bar.
|
||||
# This allows for scanning from one menubutton to the next.
|
||||
mBar.tk_menuBar(File_button, Edit_button)
|
||||
|
||||
root.title('menu demo')
|
||||
root.iconname('packer')
|
||||
|
||||
root.mainloop()
|
||||
28
Demo/tkinter/matt/not-what-you-might-think-1.py
Normal file
28
Demo/tkinter/matt/not-what-you-might-think-1.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from Tkinter import *
|
||||
|
||||
|
||||
class Test(Frame):
|
||||
def createWidgets(self):
|
||||
|
||||
self.Gpanel = Frame(self, width='1i', height='1i',
|
||||
background='green')
|
||||
self.Gpanel.pack(side=LEFT)
|
||||
|
||||
# a QUIT button
|
||||
self.Gpanel.QUIT = Button(self.Gpanel, text='QUIT',
|
||||
foreground='red',
|
||||
command=self.quit)
|
||||
self.Gpanel.QUIT.pack(side=LEFT)
|
||||
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
|
||||
test.master.title('packer demo')
|
||||
test.master.iconname('packer')
|
||||
|
||||
test.mainloop()
|
||||
30
Demo/tkinter/matt/not-what-you-might-think-2.py
Normal file
30
Demo/tkinter/matt/not-what-you-might-think-2.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from Tkinter import *
|
||||
|
||||
|
||||
class Test(Frame):
|
||||
def createWidgets(self):
|
||||
|
||||
self.Gpanel = Frame(self, width='1i', height='1i',
|
||||
background='green')
|
||||
|
||||
# this line turns off the recalculation of geometry by masters.
|
||||
self.Gpanel.propagate(0)
|
||||
|
||||
self.Gpanel.pack(side=LEFT)
|
||||
|
||||
# a QUIT button
|
||||
self.Gpanel.QUIT = Button(self.Gpanel, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.Gpanel.QUIT.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
|
||||
test.master.title('packer demo')
|
||||
test.master.iconname('packer')
|
||||
|
||||
test.mainloop()
|
||||
41
Demo/tkinter/matt/packer-and-placer-together.py
Normal file
41
Demo/tkinter/matt/packer-and-placer-together.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from Tkinter import *
|
||||
|
||||
# This is a program that tests the placer geom manager in conjunction with
|
||||
# the packer. The background (green) is packed, while the widget inside is placed
|
||||
|
||||
|
||||
def do_motion(event):
|
||||
app.button.place(x=event.x, y=event.y)
|
||||
|
||||
def dothis():
|
||||
print 'calling me!'
|
||||
|
||||
def createWidgets(top):
|
||||
# make a frame. Note that the widget is 200 x 200
|
||||
# and the window containing is 400x400. We do this
|
||||
# simply to show that this is possible. The rest of the
|
||||
# area is inaccesssible.
|
||||
f = Frame(top, width=200, height=200, background='green')
|
||||
|
||||
# note that we use a different manager here.
|
||||
# This way, the top level frame widget resizes when the
|
||||
# application window does.
|
||||
f.pack(fill=BOTH, expand=1)
|
||||
|
||||
# now make a button
|
||||
f.button = Button(f, foreground='red', text='amazing', command=dothis)
|
||||
|
||||
# and place it so that the nw corner is
|
||||
# 1/2 way along the top X edge of its' parent
|
||||
f.button.place(relx=0.5, rely=0.0, anchor=NW)
|
||||
|
||||
# allow the user to move the button SUIT-style.
|
||||
f.bind('<Control-Shift-Motion>', do_motion)
|
||||
|
||||
return f
|
||||
|
||||
root = Tk()
|
||||
app = createWidgets(root)
|
||||
root.geometry("400x400")
|
||||
root.maxsize(1000, 1000)
|
||||
root.mainloop()
|
||||
32
Demo/tkinter/matt/packer-simple.py
Normal file
32
Demo/tkinter/matt/packer-simple.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from Tkinter import *
|
||||
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print self.hi_there["command"]
|
||||
|
||||
def createWidgets(self):
|
||||
# a hello button
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
self.hi_there = Button(self, text='Hello',
|
||||
command=self.printit)
|
||||
self.hi_there.pack(side=LEFT)
|
||||
|
||||
# note how Packer defaults to side=TOP
|
||||
|
||||
self.guy2 = Button(self, text='button 2')
|
||||
self.guy2.pack()
|
||||
|
||||
self.guy3 = Button(self, text='button 3')
|
||||
self.guy3.pack()
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
39
Demo/tkinter/matt/placer-simple.py
Normal file
39
Demo/tkinter/matt/placer-simple.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from Tkinter import *
|
||||
|
||||
# This is a program that tests the placer geom manager
|
||||
|
||||
def do_motion(event):
|
||||
app.button.place(x=event.x, y=event.y)
|
||||
|
||||
def dothis():
|
||||
print 'calling me!'
|
||||
|
||||
def createWidgets(top):
|
||||
# make a frame. Note that the widget is 200 x 200
|
||||
# and the window containing is 400x400. We do this
|
||||
# simply to show that this is possible. The rest of the
|
||||
# area is inaccesssible.
|
||||
f = Frame(top, width=200, height=200, background='green')
|
||||
|
||||
# place it so the upper left hand corner of
|
||||
# the frame is in the upper left corner of
|
||||
# the parent
|
||||
f.place(relx=0.0, rely=0.0)
|
||||
|
||||
# now make a button
|
||||
f.button = Button(f, foreground='red', text='amazing', command=dothis)
|
||||
|
||||
# and place it so that the nw corner is
|
||||
# 1/2 way along the top X edge of its' parent
|
||||
f.button.place(relx=0.5, rely=0.0, anchor=NW)
|
||||
|
||||
# allow the user to move the button SUIT-style.
|
||||
f.bind('<Control-Shift-Motion>', do_motion)
|
||||
|
||||
return f
|
||||
|
||||
root = Tk()
|
||||
app = createWidgets(root)
|
||||
root.geometry("400x400")
|
||||
root.maxsize(1000, 1000)
|
||||
root.mainloop()
|
||||
54
Demo/tkinter/matt/pong-demo-1.py
Normal file
54
Demo/tkinter/matt/pong-demo-1.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from Tkinter import *
|
||||
|
||||
import string
|
||||
|
||||
|
||||
class Pong(Frame):
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
## The playing field
|
||||
self.draw = Canvas(self, width="5i", height="5i")
|
||||
|
||||
## The speed control for the ball
|
||||
self.speed = Scale(self, orient=HORIZONTAL, label="ball speed",
|
||||
from_=-100, to=100)
|
||||
|
||||
self.speed.pack(side=BOTTOM, fill=X)
|
||||
|
||||
# The ball
|
||||
self.ball = self.draw.create_oval("0i", "0i", "0.10i", "0.10i",
|
||||
fill="red")
|
||||
self.x = 0.05
|
||||
self.y = 0.05
|
||||
self.velocity_x = 0.3
|
||||
self.velocity_y = 0.5
|
||||
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
def moveBall(self, *args):
|
||||
if (self.x > 5.0) or (self.x < 0.0):
|
||||
self.velocity_x = -1.0 * self.velocity_x
|
||||
if (self.y > 5.0) or (self.y < 0.0):
|
||||
self.velocity_y = -1.0 * self.velocity_y
|
||||
|
||||
deltax = (self.velocity_x * self.speed.get() / 100.0)
|
||||
deltay = (self.velocity_y * self.speed.get() / 100.0)
|
||||
self.x = self.x + deltax
|
||||
self.y = self.y + deltay
|
||||
|
||||
self.draw.move(self.ball, "%ri" % deltax, "%ri" % deltay)
|
||||
self.after(10, self.moveBall)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
self.after(10, self.moveBall)
|
||||
|
||||
|
||||
game = Pong()
|
||||
|
||||
game.mainloop()
|
||||
61
Demo/tkinter/matt/printing-coords-of-items.py
Normal file
61
Demo/tkinter/matt/printing-coords-of-items.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from Tkinter import *
|
||||
|
||||
# this file demonstrates the creation of widgets as part of a canvas object
|
||||
|
||||
class Test(Frame):
|
||||
###################################################################
|
||||
###### Event callbacks for THE CANVAS (not the stuff drawn on it)
|
||||
###################################################################
|
||||
def mouseDown(self, event):
|
||||
# see if we're inside a dot. If we are, it
|
||||
# gets tagged as CURRENT for free by tk.
|
||||
|
||||
if not event.widget.find_withtag(CURRENT):
|
||||
# there is no dot here, so we can make one,
|
||||
# and bind some interesting behavior to it.
|
||||
# ------
|
||||
# create a dot, and mark it as current
|
||||
fred = self.draw.create_oval(
|
||||
event.x - 10, event.y -10, event.x +10, event.y + 10,
|
||||
fill="green")
|
||||
self.draw.tag_bind(fred, "<Enter>", self.mouseEnter)
|
||||
self.draw.tag_bind(fred, "<Leave>", self.mouseLeave)
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
def mouseMove(self, event):
|
||||
self.draw.move(CURRENT, event.x - self.lastx, event.y - self.lasty)
|
||||
self.lastx = event.x
|
||||
self.lasty = event.y
|
||||
|
||||
###################################################################
|
||||
###### Event callbacks for canvas ITEMS (stuff drawn on the canvas)
|
||||
###################################################################
|
||||
def mouseEnter(self, event):
|
||||
# the "current" tag is applied to the object the cursor is over.
|
||||
# this happens automatically.
|
||||
self.draw.itemconfig(CURRENT, fill="red")
|
||||
print self.draw.coords(CURRENT)
|
||||
|
||||
def mouseLeave(self, event):
|
||||
# the "current" tag is applied to the object the cursor is over.
|
||||
# this happens automatically.
|
||||
self.draw.itemconfig(CURRENT, fill="blue")
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
self.draw = Canvas(self, width="5i", height="5i")
|
||||
self.draw.pack(side=LEFT)
|
||||
|
||||
Widget.bind(self.draw, "<1>", self.mouseDown)
|
||||
Widget.bind(self.draw, "<B1-Motion>", self.mouseMove)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
62
Demo/tkinter/matt/radiobutton-simple.py
Normal file
62
Demo/tkinter/matt/radiobutton-simple.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from Tkinter import *
|
||||
|
||||
# This is a demo program that shows how to
|
||||
# create radio buttons and how to get other widgets to
|
||||
# share the information in a radio button.
|
||||
#
|
||||
# There are other ways of doing this too, but
|
||||
# the "variable" option of radiobuttons seems to be the easiest.
|
||||
#
|
||||
# note how each button has a value it sets the variable to as it gets hit.
|
||||
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
|
||||
self.flavor = StringVar()
|
||||
self.flavor.set("chocolate")
|
||||
|
||||
self.radioframe = Frame(self)
|
||||
self.radioframe.pack()
|
||||
|
||||
# 'text' is the label
|
||||
# 'variable' is the name of the variable that all these radio buttons share
|
||||
# 'value' is the value this variable takes on when the radio button is selected
|
||||
# 'anchor' makes the text appear left justified (default is centered. ick)
|
||||
self.radioframe.choc = Radiobutton(
|
||||
self.radioframe, text="Chocolate Flavor",
|
||||
variable=self.flavor, value="chocolate",
|
||||
anchor=W)
|
||||
self.radioframe.choc.pack(fill=X)
|
||||
|
||||
self.radioframe.straw = Radiobutton(
|
||||
self.radioframe, text="Strawberry Flavor",
|
||||
variable=self.flavor, value="strawberry",
|
||||
anchor=W)
|
||||
self.radioframe.straw.pack(fill=X)
|
||||
|
||||
self.radioframe.lemon = Radiobutton(
|
||||
self.radioframe, text="Lemon Flavor",
|
||||
variable=self.flavor, value="lemon",
|
||||
anchor=W)
|
||||
self.radioframe.lemon.pack(fill=X)
|
||||
|
||||
# this is a text entry that lets you type in the name of a flavor too.
|
||||
self.entry = Entry(self, textvariable=self.flavor)
|
||||
self.entry.pack(fill=X)
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
58
Demo/tkinter/matt/rubber-band-box-demo-1.py
Normal file
58
Demo/tkinter/matt/rubber-band-box-demo-1.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from Tkinter import *
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT',
|
||||
background='red',
|
||||
foreground='white',
|
||||
height=3,
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
|
||||
self.canvasObject = Canvas(self, width="5i", height="5i")
|
||||
self.canvasObject.pack(side=LEFT)
|
||||
|
||||
def mouseDown(self, event):
|
||||
# canvas x and y take the screen coords from the event and translate
|
||||
# them into the coordinate system of the canvas object
|
||||
self.startx = self.canvasObject.canvasx(event.x)
|
||||
self.starty = self.canvasObject.canvasy(event.y)
|
||||
|
||||
def mouseMotion(self, event):
|
||||
# canvas x and y take the screen coords from the event and translate
|
||||
# them into the coordinate system of the canvas object
|
||||
x = self.canvasObject.canvasx(event.x)
|
||||
y = self.canvasObject.canvasy(event.y)
|
||||
|
||||
if (self.startx != event.x) and (self.starty != event.y) :
|
||||
self.canvasObject.delete(self.rubberbandBox)
|
||||
self.rubberbandBox = self.canvasObject.create_rectangle(
|
||||
self.startx, self.starty, x, y)
|
||||
# this flushes the output, making sure that
|
||||
# the rectangle makes it to the screen
|
||||
# before the next event is handled
|
||||
self.update_idletasks()
|
||||
|
||||
def mouseUp(self, event):
|
||||
self.canvasObject.delete(self.rubberbandBox)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
# this is a "tagOrId" for the rectangle we draw on the canvas
|
||||
self.rubberbandBox = None
|
||||
|
||||
# and the bindings that make it work..
|
||||
Widget.bind(self.canvasObject, "<Button-1>", self.mouseDown)
|
||||
Widget.bind(self.canvasObject, "<Button1-Motion>", self.mouseMotion)
|
||||
Widget.bind(self.canvasObject, "<Button1-ButtonRelease>", self.mouseUp)
|
||||
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
51
Demo/tkinter/matt/rubber-line-demo-1.py
Normal file
51
Demo/tkinter/matt/rubber-line-demo-1.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from Tkinter import *
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT',
|
||||
background='red',
|
||||
foreground='white',
|
||||
height=3,
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=BOTTOM, fill=BOTH)
|
||||
|
||||
self.canvasObject = Canvas(self, width="5i", height="5i")
|
||||
self.canvasObject.pack(side=LEFT)
|
||||
|
||||
def mouseDown(self, event):
|
||||
# canvas x and y take the screen coords from the event and translate
|
||||
# them into the coordinate system of the canvas object
|
||||
self.startx = self.canvasObject.canvasx(event.x)
|
||||
self.starty = self.canvasObject.canvasy(event.y)
|
||||
|
||||
def mouseMotion(self, event):
|
||||
# canvas x and y take the screen coords from the event and translate
|
||||
# them into the coordinate system of the canvas object
|
||||
x = self.canvasObject.canvasx(event.x)
|
||||
y = self.canvasObject.canvasy(event.y)
|
||||
|
||||
if (self.startx != event.x) and (self.starty != event.y) :
|
||||
self.canvasObject.delete(self.rubberbandLine)
|
||||
self.rubberbandLine = self.canvasObject.create_line(
|
||||
self.startx, self.starty, x, y)
|
||||
# this flushes the output, making sure that
|
||||
# the rectangle makes it to the screen
|
||||
# before the next event is handled
|
||||
self.update_idletasks()
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
# this is a "tagOrId" for the rectangle we draw on the canvas
|
||||
self.rubberbandLine = None
|
||||
Widget.bind(self.canvasObject, "<Button-1>", self.mouseDown)
|
||||
Widget.bind(self.canvasObject, "<Button1-Motion>", self.mouseMotion)
|
||||
|
||||
|
||||
test = Test()
|
||||
|
||||
test.mainloop()
|
||||
36
Demo/tkinter/matt/slider-demo-1.py
Normal file
36
Demo/tkinter/matt/slider-demo-1.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from Tkinter import *
|
||||
|
||||
# shows how to make a slider, set and get its value under program control
|
||||
|
||||
|
||||
class Test(Frame):
|
||||
def print_value(self, val):
|
||||
print "slider now at", val
|
||||
|
||||
def reset(self):
|
||||
self.slider.set(0)
|
||||
|
||||
def createWidgets(self):
|
||||
self.slider = Scale(self, from_=0, to=100,
|
||||
orient=HORIZONTAL,
|
||||
length="3i",
|
||||
label="happy slider",
|
||||
command=self.print_value)
|
||||
|
||||
self.reset = Button(self, text='reset slider',
|
||||
command=self.reset)
|
||||
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
|
||||
self.slider.pack(side=LEFT)
|
||||
self.reset.pack(side=LEFT)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
28
Demo/tkinter/matt/subclass-existing-widgets.py
Normal file
28
Demo/tkinter/matt/subclass-existing-widgets.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from Tkinter import *
|
||||
|
||||
# This is a program that makes a simple two button application
|
||||
|
||||
|
||||
class New_Button(Button):
|
||||
def callback(self):
|
||||
print self.counter
|
||||
self.counter = self.counter + 1
|
||||
|
||||
def createWidgets(top):
|
||||
f = Frame(top)
|
||||
f.pack()
|
||||
f.QUIT = Button(f, text='QUIT', foreground='red', command=top.quit)
|
||||
|
||||
f.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
# a hello button
|
||||
f.hi_there = New_Button(f, text='Hello')
|
||||
# we do this on a different line because we need to reference f.hi_there
|
||||
f.hi_there.config(command=f.hi_there.callback)
|
||||
f.hi_there.pack(side=LEFT)
|
||||
f.hi_there.counter = 43
|
||||
|
||||
|
||||
root = Tk()
|
||||
createWidgets(root)
|
||||
root.mainloop()
|
||||
110
Demo/tkinter/matt/two-radio-groups.py
Normal file
110
Demo/tkinter/matt/two-radio-groups.py
Normal file
@@ -0,0 +1,110 @@
|
||||
from Tkinter import *
|
||||
|
||||
# The way to think about this is that each radio button menu
|
||||
# controls a different variable -- clicking on one of the
|
||||
# mutually exclusive choices in a radiobutton assigns some value
|
||||
# to an application variable you provide. When you define a
|
||||
# radiobutton menu choice, you have the option of specifying the
|
||||
# name of a varaible and value to assign to that variable when
|
||||
# that choice is selected. This clever mechanism relieves you,
|
||||
# the programmer, from having to write a dumb callback that
|
||||
# probably wouldn't have done anything more than an assignment
|
||||
# anyway. The Tkinter options for this follow their Tk
|
||||
# counterparts:
|
||||
# {"variable" : my_flavor_variable, "value" : "strawberry"}
|
||||
# where my_flavor_variable is an instance of one of the
|
||||
# subclasses of Variable, provided in Tkinter.py (there is
|
||||
# StringVar(), IntVar(), DoubleVar() and BooleanVar() to choose
|
||||
# from)
|
||||
|
||||
|
||||
|
||||
def makePoliticalParties(var):
|
||||
# make menu button
|
||||
Radiobutton_button = Menubutton(mBar, text='Political Party',
|
||||
underline=0)
|
||||
Radiobutton_button.pack(side=LEFT, padx='2m')
|
||||
|
||||
# the primary pulldown
|
||||
Radiobutton_button.menu = Menu(Radiobutton_button)
|
||||
|
||||
Radiobutton_button.menu.add_radiobutton(label='Republican',
|
||||
variable=var, value=1)
|
||||
|
||||
Radiobutton_button.menu.add('radiobutton', {'label': 'Democrat',
|
||||
'variable' : var,
|
||||
'value' : 2})
|
||||
|
||||
Radiobutton_button.menu.add('radiobutton', {'label': 'Libertarian',
|
||||
'variable' : var,
|
||||
'value' : 3})
|
||||
|
||||
var.set(2)
|
||||
|
||||
# set up a pointer from the file menubutton back to the file menu
|
||||
Radiobutton_button['menu'] = Radiobutton_button.menu
|
||||
|
||||
return Radiobutton_button
|
||||
|
||||
|
||||
def makeFlavors(var):
|
||||
# make menu button
|
||||
Radiobutton_button = Menubutton(mBar, text='Flavors',
|
||||
underline=0)
|
||||
Radiobutton_button.pack(side=LEFT, padx='2m')
|
||||
|
||||
# the primary pulldown
|
||||
Radiobutton_button.menu = Menu(Radiobutton_button)
|
||||
|
||||
Radiobutton_button.menu.add_radiobutton(label='Strawberry',
|
||||
variable=var, value='Strawberry')
|
||||
|
||||
Radiobutton_button.menu.add_radiobutton(label='Chocolate',
|
||||
variable=var, value='Chocolate')
|
||||
|
||||
Radiobutton_button.menu.add_radiobutton(label='Rocky Road',
|
||||
variable=var, value='Rocky Road')
|
||||
|
||||
# choose a default
|
||||
var.set("Chocolate")
|
||||
|
||||
# set up a pointer from the file menubutton back to the file menu
|
||||
Radiobutton_button['menu'] = Radiobutton_button.menu
|
||||
|
||||
return Radiobutton_button
|
||||
|
||||
|
||||
def printStuff():
|
||||
print "party is", party.get()
|
||||
print "flavor is", flavor.get()
|
||||
print
|
||||
|
||||
#################################################
|
||||
#### Main starts here ...
|
||||
root = Tk()
|
||||
|
||||
|
||||
# make a menu bar
|
||||
mBar = Frame(root, relief=RAISED, borderwidth=2)
|
||||
mBar.pack(fill=X)
|
||||
|
||||
# make two application variables,
|
||||
# one to control each radio button set
|
||||
party = IntVar()
|
||||
flavor = StringVar()
|
||||
|
||||
Radiobutton_button = makePoliticalParties(party)
|
||||
Radiobutton_button2 = makeFlavors(flavor)
|
||||
|
||||
# finally, install the buttons in the menu bar.
|
||||
# This allows for scanning from one menubutton to the next.
|
||||
mBar.tk_menuBar(Radiobutton_button, Radiobutton_button2)
|
||||
|
||||
b = Button(root, text="print party and flavor", foreground="red",
|
||||
command=printStuff)
|
||||
b.pack(side=TOP)
|
||||
|
||||
root.title('menu demo')
|
||||
root.iconname('menu demo')
|
||||
|
||||
root.mainloop()
|
||||
35
Demo/tkinter/matt/window-creation-more.py
Normal file
35
Demo/tkinter/matt/window-creation-more.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from Tkinter import *
|
||||
|
||||
# this shows how to create a new window with a button in it
|
||||
# that can create new windows
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def makeWindow(self):
|
||||
fred = Toplevel()
|
||||
fred.label = Button(fred,
|
||||
text="This is window number %d." % self.windownum,
|
||||
command=self.makeWindow)
|
||||
fred.label.pack()
|
||||
self.windownum = self.windownum + 1
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
# a hello button
|
||||
self.hi_there = Button(self, text='Make a New Window',
|
||||
command=self.makeWindow)
|
||||
self.hi_there.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.windownum = 0
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
31
Demo/tkinter/matt/window-creation-simple.py
Normal file
31
Demo/tkinter/matt/window-creation-simple.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from Tkinter import *
|
||||
|
||||
# this shows how to spawn off new windows at a button press
|
||||
|
||||
class Test(Frame):
|
||||
def printit(self):
|
||||
print "hi"
|
||||
|
||||
def makeWindow(self):
|
||||
fred = Toplevel()
|
||||
fred.label = Label(fred, text="Here's a new window")
|
||||
fred.label.pack()
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = Button(self, text='QUIT', foreground='red',
|
||||
command=self.quit)
|
||||
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
# a hello button
|
||||
self.hi_there = Button(self, text='Make a New Window',
|
||||
command=self.makeWindow)
|
||||
self.hi_there.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
45
Demo/tkinter/matt/window-creation-w-location.py
Normal file
45
Demo/tkinter/matt/window-creation-w-location.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from Tkinter import *
|
||||
|
||||
import sys
|
||||
##sys.path.append("/users/mjc4y/projects/python/tkinter/utils")
|
||||
##from TkinterUtils import *
|
||||
|
||||
# this shows how to create a new window with a button in it that
|
||||
# can create new windows
|
||||
|
||||
class QuitButton(Button):
|
||||
def __init__(self, master, *args, **kwargs):
|
||||
if not kwargs.has_key("text"):
|
||||
kwargs["text"] = "QUIT"
|
||||
if not kwargs.has_key("command"):
|
||||
kwargs["command"] = master.quit
|
||||
apply(Button.__init__, (self, master) + args, kwargs)
|
||||
|
||||
class Test(Frame):
|
||||
def makeWindow(self, *args):
|
||||
fred = Toplevel()
|
||||
|
||||
fred.label = Canvas (fred, width="2i", height="2i")
|
||||
|
||||
fred.label.create_line("0", "0", "2i", "2i")
|
||||
fred.label.create_line("0", "2i", "2i", "0")
|
||||
fred.label.pack()
|
||||
|
||||
##centerWindow(fred, self.master)
|
||||
|
||||
def createWidgets(self):
|
||||
self.QUIT = QuitButton(self)
|
||||
self.QUIT.pack(side=LEFT, fill=BOTH)
|
||||
|
||||
self.makeWindow = Button(self, text='Make a New Window',
|
||||
width=50, height=20,
|
||||
command=self.makeWindow)
|
||||
self.makeWindow.pack(side=LEFT)
|
||||
|
||||
def __init__(self, master=None):
|
||||
Frame.__init__(self, master)
|
||||
Pack.config(self)
|
||||
self.createWidgets()
|
||||
|
||||
test = Test()
|
||||
test.mainloop()
|
||||
46
Demo/tkinter/ttk/combo_themes.py
Normal file
46
Demo/tkinter/ttk/combo_themes.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""Ttk Theme Selector.
|
||||
|
||||
Although it is a theme selector, you won't notice many changes since
|
||||
there is only a combobox and a frame around.
|
||||
"""
|
||||
import ttk
|
||||
|
||||
class App(ttk.Frame):
|
||||
def __init__(self):
|
||||
ttk.Frame.__init__(self)
|
||||
|
||||
self.style = ttk.Style()
|
||||
self._setup_widgets()
|
||||
|
||||
def _change_theme(self, event):
|
||||
if event.widget.current(): # value #0 is not a theme
|
||||
newtheme = event.widget.get()
|
||||
# change to the new theme and refresh all the widgets
|
||||
self.style.theme_use(newtheme)
|
||||
|
||||
def _setup_widgets(self):
|
||||
themes = list(self.style.theme_names())
|
||||
themes.insert(0, "Pick a theme")
|
||||
# Create a readonly Combobox which will display 4 values at max,
|
||||
# which will cause it to create a scrollbar if there are more
|
||||
# than 4 values in total.
|
||||
themes_combo = ttk.Combobox(self, values=themes, state="readonly",
|
||||
height=4)
|
||||
themes_combo.set(themes[0]) # sets the combobox value to "Pick a theme"
|
||||
# Combobox widget generates a <<ComboboxSelected>> virtual event
|
||||
# when the user selects an element. This event is generated after
|
||||
# the listbox is unposted (after you select an item, the combobox's
|
||||
# listbox disappears, then it is said that listbox is now unposted).
|
||||
themes_combo.bind("<<ComboboxSelected>>", self._change_theme)
|
||||
themes_combo.pack(fill='x')
|
||||
|
||||
self.pack(fill='both', expand=1)
|
||||
|
||||
|
||||
def main():
|
||||
app = App()
|
||||
app.master.title("Ttk Combobox")
|
||||
app.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
93
Demo/tkinter/ttk/dirbrowser.py
Normal file
93
Demo/tkinter/ttk/dirbrowser.py
Normal file
@@ -0,0 +1,93 @@
|
||||
"""A directory browser using Ttk Treeview.
|
||||
|
||||
Based on the demo found in Tk 8.5 library/demos/browse
|
||||
"""
|
||||
import os
|
||||
import glob
|
||||
import Tkinter
|
||||
import ttk
|
||||
|
||||
def populate_tree(tree, node):
|
||||
if tree.set(node, "type") != 'directory':
|
||||
return
|
||||
|
||||
path = tree.set(node, "fullpath")
|
||||
tree.delete(*tree.get_children(node))
|
||||
|
||||
parent = tree.parent(node)
|
||||
special_dirs = [] if parent else glob.glob('.') + glob.glob('..')
|
||||
|
||||
for p in special_dirs + os.listdir(path):
|
||||
ptype = None
|
||||
p = os.path.join(path, p).replace('\\', '/')
|
||||
if os.path.isdir(p): ptype = "directory"
|
||||
elif os.path.isfile(p): ptype = "file"
|
||||
|
||||
fname = os.path.split(p)[1]
|
||||
id = tree.insert(node, "end", text=fname, values=[p, ptype])
|
||||
|
||||
if ptype == 'directory':
|
||||
if fname not in ('.', '..'):
|
||||
tree.insert(id, 0, text="dummy")
|
||||
tree.item(id, text=fname)
|
||||
elif ptype == 'file':
|
||||
size = os.stat(p).st_size
|
||||
tree.set(id, "size", "%d bytes" % size)
|
||||
|
||||
|
||||
def populate_roots(tree):
|
||||
dir = os.path.abspath('.').replace('\\', '/')
|
||||
node = tree.insert('', 'end', text=dir, values=[dir, "directory"])
|
||||
populate_tree(tree, node)
|
||||
|
||||
def update_tree(event):
|
||||
tree = event.widget
|
||||
populate_tree(tree, tree.focus())
|
||||
|
||||
def change_dir(event):
|
||||
tree = event.widget
|
||||
node = tree.focus()
|
||||
if tree.parent(node):
|
||||
path = os.path.abspath(tree.set(node, "fullpath"))
|
||||
if os.path.isdir(path):
|
||||
os.chdir(path)
|
||||
tree.delete(tree.get_children(''))
|
||||
populate_roots(tree)
|
||||
|
||||
def autoscroll(sbar, first, last):
|
||||
"""Hide and show scrollbar as needed."""
|
||||
first, last = float(first), float(last)
|
||||
if first <= 0 and last >= 1:
|
||||
sbar.grid_remove()
|
||||
else:
|
||||
sbar.grid()
|
||||
sbar.set(first, last)
|
||||
|
||||
root = Tkinter.Tk()
|
||||
|
||||
vsb = ttk.Scrollbar(orient="vertical")
|
||||
hsb = ttk.Scrollbar(orient="horizontal")
|
||||
|
||||
tree = ttk.Treeview(columns=("fullpath", "type", "size"),
|
||||
displaycolumns="size", yscrollcommand=lambda f, l: autoscroll(vsb, f, l),
|
||||
xscrollcommand=lambda f, l:autoscroll(hsb, f, l))
|
||||
|
||||
vsb['command'] = tree.yview
|
||||
hsb['command'] = tree.xview
|
||||
|
||||
tree.heading("#0", text="Directory Structure", anchor='w')
|
||||
tree.heading("size", text="File Size", anchor='w')
|
||||
tree.column("size", stretch=0, width=100)
|
||||
|
||||
populate_roots(tree)
|
||||
tree.bind('<<TreeviewOpen>>', update_tree)
|
||||
tree.bind('<Double-Button-1>', change_dir)
|
||||
|
||||
# Arrange the tree and its scrollbars in the toplevel
|
||||
tree.grid(column=0, row=0, sticky='nswe')
|
||||
vsb.grid(column=1, row=0, sticky='ns')
|
||||
hsb.grid(column=0, row=1, sticky='ew')
|
||||
root.grid_columnconfigure(0, weight=1)
|
||||
root.grid_rowconfigure(0, weight=1)
|
||||
|
||||
root.mainloop()
|
||||
BIN
Demo/tkinter/ttk/img/close.gif
Normal file
BIN
Demo/tkinter/ttk/img/close.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 101 B |
BIN
Demo/tkinter/ttk/img/close_active.gif
Normal file
BIN
Demo/tkinter/ttk/img/close_active.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 B |
BIN
Demo/tkinter/ttk/img/close_pressed.gif
Normal file
BIN
Demo/tkinter/ttk/img/close_pressed.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 101 B |
37
Demo/tkinter/ttk/listbox_scrollcmd.py
Normal file
37
Demo/tkinter/ttk/listbox_scrollcmd.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""Sample taken from: http://www.tkdocs.com/tutorial/morewidgets.html and
|
||||
converted to Python, mainly to demonstrate xscrollcommand option.
|
||||
|
||||
grid [tk::listbox .l -yscrollcommand ".s set" -height 5] -column 0 -row 0 -sticky nwes
|
||||
grid [ttk::scrollbar .s -command ".l yview" -orient vertical] -column 1 -row 0 -sticky ns
|
||||
grid [ttk::label .stat -text "Status message here" -anchor w] -column 0 -row 1 -sticky we
|
||||
grid [ttk::sizegrip .sz] -column 1 -row 1 -sticky se
|
||||
grid columnconfigure . 0 -weight 1; grid rowconfigure . 0 -weight 1
|
||||
for {set i 0} {$i<100} {incr i} {
|
||||
.l insert end "Line $i of 100"
|
||||
}
|
||||
"""
|
||||
import Tkinter
|
||||
import ttk
|
||||
|
||||
root = Tkinter.Tk()
|
||||
|
||||
l = Tkinter.Listbox(height=5)
|
||||
l.grid(column=0, row=0, sticky='nwes')
|
||||
|
||||
s = ttk.Scrollbar(command=l.yview, orient='vertical')
|
||||
l['yscrollcommand'] = s.set
|
||||
s.grid(column=1, row=0, sticky="ns")
|
||||
|
||||
stat = ttk.Label(text="Status message here", anchor='w')
|
||||
stat.grid(column=0, row=1, sticky='we')
|
||||
|
||||
sz = ttk.Sizegrip()
|
||||
sz.grid(column=1, row=1, sticky='se')
|
||||
|
||||
root.grid_columnconfigure(0, weight=1)
|
||||
root.grid_rowconfigure(0, weight=1)
|
||||
|
||||
for i in range(100):
|
||||
l.insert('end', "Line %d of 100" % i)
|
||||
|
||||
root.mainloop()
|
||||
78
Demo/tkinter/ttk/mac_searchentry.py
Normal file
78
Demo/tkinter/ttk/mac_searchentry.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""Mac style search widget
|
||||
|
||||
Translated from Tcl code by Schelte Bron, http://wiki.tcl.tk/18188
|
||||
"""
|
||||
import Tkinter
|
||||
import ttk
|
||||
|
||||
root = Tkinter.Tk()
|
||||
|
||||
data = """
|
||||
R0lGODlhKgAaAOfnAFdZVllbWFpcWVtdWlxeW11fXF9hXmBiX2ZnZWhpZ2lraGxua25wbXJ0
|
||||
cXR2c3V3dHZ4dXh6d3x+e31/fH6AfYSGg4eJhoiKh4qMiYuNio2PjHmUqnqVq3yXrZGTkJKU
|
||||
kX+asJSWk32cuJWXlIGcs5aYlX6euZeZloOetZial4SftpqbmIWgt4GhvYahuIKivpudmYei
|
||||
uYOjv5yem4ijuoSkwIWlwYmlu56gnYamwp+hnoenw4unvaCin4ioxJCnuZykrImpxZmlsoaq
|
||||
zI2pv6KkoZGouoqqxpqms4erzaOloo6qwYurx5Kqu5untIiszqSmo5CrwoysyJeqtpOrvJyo
|
||||
tZGsw42typSsvaaopZKtxJWtvp6qt4+uy6epppOuxZCvzKiqp5quuZSvxoyx06mrqJWwx42y
|
||||
1JKxzpmwwaqsqZaxyI6z1ZqxwqutqpOzz4+01qyuq56yvpizypS00Jm0y5W10Zq1zJa20rCy
|
||||
rpu3zqizwbGzr6C3yZy4z7K0saG4yp250LO1sqK5y5660Z+70qO7zKy4xaC806S8zba4taG9
|
||||
1KW9zq66x6+7yLi6t6S/1rC8yrm7uLO8xLG9y7q8ubS9xabB2anB07K+zLW+xrO/za7CzrTA
|
||||
zrjAyLXBz77BvbbC0K/G2LjD0bnE0rLK28TGw8bIxcLL07vP28HN28rMycvOyr/T38DU4cnR
|
||||
2s/RztHT0NLU0cTY5MrW5MvX5dHX2c3Z59bY1dPb5Nbb3dLe7Nvd2t3f3NXh797g3d3j5dnl
|
||||
9OPl4eTm4+Ln6tzo9uXn5Obo5eDp8efp5uHq8uXq7ejq5+nr6OPs9Ovu6unu8O3v6+vw8+7w
|
||||
7ezx9O/x7vDy7/Hz8O/19/P18vT38/L3+fb49Pf59vX6/fj69/b7/vn7+Pr8+ff9//v9+vz/
|
||||
+/7//P//////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJZAD/ACwC
|
||||
AAIAKAAWAAAI/gD/CRz4bwUGCg8eQFjIsGHDBw4iTLAQgqBFgisuePCiyJOpUyBDihRpypMi
|
||||
Lx8qaLhIMIyGFZ5sAUsmjZrNmzhzWpO2DJgtTysqfGDpxoMbW8ekeQsXzty4p1CjRjUXrps3
|
||||
asJsuclQ4uKKSbamMR3n1JzZs2jRkh1HzuxVXX8y4CDYAwqua+DInVrRwMGJU2kDp31KThy1
|
||||
XGWGDlxhi1rTPAUICBBAoEAesoIzn6Vm68MKgVAUHftmzhOCBCtQwQKSoABgzZnJdSMmyIPA
|
||||
FbCotdUQAIhNa9B6DPCAGbZac+SowVIMRVe4pwkA4GpqDlwuAAmMZx4nTtfnf1mO5JEDNy46
|
||||
MHJkxQEDgKC49rPjwC0bqGaZuOoZAKjBPE4NgAzUvYcWOc0QZF91imAnCDHJ5JFAAJN0I2Ba
|
||||
4iRDUC/gOEVNDwIUcEABCAgAAATUTIgWOMBYRFp80ghiAQIIVAAEAwJIYI2JZnUji0XSYAYO
|
||||
NcsQA8wy0hCTwAASXGOiONFcxAtpTokTHznfiLMNMAkcAMuE43jDC0vLeGOWe2R5o4sn1LgH
|
||||
GzkWsvTPMgEOaA433Ag4TjjMuDkQMNi0tZ12sqWoJ0HATMPNffAZZ6U0wLAyqJ62RGoLLrhI
|
||||
aqmlpzwaEAAh+QQJZAD/ACwAAAAAKgAaAAAI/gD/CRw40JEhQoEC+fGjcOHCMRAjRkxDsKLF
|
||||
f5YcAcID582ZjyBDJhmZZIjJIUySEDHiBMhFghrtdNnRAgSHmzhz6sTZQcSLITx+CHn5bxSk
|
||||
Nz5MCMGy55CjTVCjbuJEtSrVQ3uwqDBRQwrFi476SHHxow8qXcemVbPGtm21t3CnTaP27Jgu
|
||||
VHtuiIjBsuImQkRiiEEFTNo2cOTMKV7MuLE5cN68QUOGSgwKG1EqJqJDY8+rZt8UjxtNunTj
|
||||
cY3DgZOWS46KIFgGjiI0ZIsqaqNNjWjgYMUpx8Adc3v2aosNMAI1DbqyI9WycOb4IAggQEAB
|
||||
A3lQBxet/TG4cMpI/tHwYeSfIzxM0uTKNs7UgAQrYL1akaDA7+3bueVqY4NJlUhIcQLNYx8E
|
||||
AIQ01mwjTQ8DeNAdfouNA8440GBCQxJY3MEGD6p4Y844CQCAizcSgpMLAAlAuJ03qOyQRBR3
|
||||
nEHEK+BMGKIui4kDDAAIPKiiYuSYSMQQRCDCxhiziPMYBgDkEaEaAGQA3Y+MjUPOLFoMoUUh
|
||||
cKxRC4ngeILiH8Qkk0cCAUzSDZWpzbLEE1EwggcYqWCj2DNADFDAAQUgIAAAEFDDJmPYqNJF
|
||||
F1s4cscTmCDjDTjdSPOHBQggUAEQDAgggTWDPoYMJkFoUdRmddyyjWLeULMMMcAsIw0x4wkM
|
||||
IME1g25zyxpHxFYUHmyIggw4H4ojITnfiLMNMAkcAAub4BQjihRdDGTJHmvc4Qo1wD6Imje6
|
||||
eILbj+BQ4wqu5Q3ECSJ0FOKKMtv4mBg33Pw4zjbKuBIIE1xYpIkhdQQiyi7OtAucj6dt48wu
|
||||
otQhBRa6VvSJIRwhIkotvgRTzMUYZ6xxMcj4QkspeKDxxRhEmUfIHWjAgQcijEDissuXvCyz
|
||||
zH7Q8YQURxDhUsn/bCInR3AELfTQZBRt9BBJkCGFFVhMwTNBlnBCSCGEIJQQIAklZMXWRBAR
|
||||
RRRWENHwRQEBADs="""
|
||||
|
||||
|
||||
s1 = Tkinter.PhotoImage("search1", data=data, format="gif -index 0")
|
||||
s2 = Tkinter.PhotoImage("search2", data=data, format="gif -index 1")
|
||||
|
||||
style = ttk.Style()
|
||||
|
||||
style.element_create("Search.field", "image", "search1",
|
||||
("focus", "search2"), border=[22, 7, 14], sticky="ew")
|
||||
|
||||
style.layout("Search.entry", [
|
||||
("Search.field", {"sticky": "nswe", "border": 1, "children":
|
||||
[("Entry.padding", {"sticky": "nswe", "children":
|
||||
[("Entry.textarea", {"sticky": "nswe"})]
|
||||
})]
|
||||
})]
|
||||
)
|
||||
|
||||
style.configure("Search.entry", background="#b2b2b2")
|
||||
|
||||
root.configure(background="#b2b2b2")
|
||||
|
||||
e1 = ttk.Entry(style="Search.entry", width=20)
|
||||
e2 = ttk.Entry(style="Search.entry", width=20)
|
||||
|
||||
e1.grid(padx=10, pady=10)
|
||||
e2.grid(padx=10, pady=10)
|
||||
|
||||
root.mainloop()
|
||||
78
Demo/tkinter/ttk/notebook_closebtn.py
Normal file
78
Demo/tkinter/ttk/notebook_closebtn.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""A Ttk Notebook with close buttons.
|
||||
|
||||
Based on an example by patthoyts, http://paste.tclers.tk/896
|
||||
"""
|
||||
import os
|
||||
import Tkinter
|
||||
import ttk
|
||||
|
||||
root = Tkinter.Tk()
|
||||
|
||||
imgdir = os.path.join(os.path.dirname(__file__), 'img')
|
||||
i1 = Tkinter.PhotoImage("img_close", file=os.path.join(imgdir, 'close.gif'))
|
||||
i2 = Tkinter.PhotoImage("img_closeactive",
|
||||
file=os.path.join(imgdir, 'close_active.gif'))
|
||||
i3 = Tkinter.PhotoImage("img_closepressed",
|
||||
file=os.path.join(imgdir, 'close_pressed.gif'))
|
||||
|
||||
style = ttk.Style()
|
||||
|
||||
style.element_create("close", "image", "img_close",
|
||||
("active", "pressed", "!disabled", "img_closepressed"),
|
||||
("active", "!disabled", "img_closeactive"), border=8, sticky='')
|
||||
|
||||
style.layout("ButtonNotebook", [("ButtonNotebook.client", {"sticky": "nswe"})])
|
||||
style.layout("ButtonNotebook.Tab", [
|
||||
("ButtonNotebook.tab", {"sticky": "nswe", "children":
|
||||
[("ButtonNotebook.padding", {"side": "top", "sticky": "nswe",
|
||||
"children":
|
||||
[("ButtonNotebook.focus", {"side": "top", "sticky": "nswe",
|
||||
"children":
|
||||
[("ButtonNotebook.label", {"side": "left", "sticky": ''}),
|
||||
("ButtonNotebook.close", {"side": "left", "sticky": ''})]
|
||||
})]
|
||||
})]
|
||||
})]
|
||||
)
|
||||
|
||||
def btn_press(event):
|
||||
x, y, widget = event.x, event.y, event.widget
|
||||
elem = widget.identify(x, y)
|
||||
index = widget.index("@%d,%d" % (x, y))
|
||||
|
||||
if "close" in elem:
|
||||
widget.state(['pressed'])
|
||||
widget.pressed_index = index
|
||||
|
||||
def btn_release(event):
|
||||
x, y, widget = event.x, event.y, event.widget
|
||||
|
||||
if not widget.instate(['pressed']):
|
||||
return
|
||||
|
||||
elem = widget.identify(x, y)
|
||||
index = widget.index("@%d,%d" % (x, y))
|
||||
|
||||
if "close" in elem and widget.pressed_index == index:
|
||||
widget.forget(index)
|
||||
widget.event_generate("<<NotebookClosedTab>>")
|
||||
|
||||
widget.state(["!pressed"])
|
||||
widget.pressed_index = None
|
||||
|
||||
|
||||
root.bind_class("TNotebook", "<ButtonPress-1>", btn_press, True)
|
||||
root.bind_class("TNotebook", "<ButtonRelease-1>", btn_release)
|
||||
|
||||
# create a ttk notebook with our custom style, and add some tabs to it
|
||||
nb = ttk.Notebook(width=200, height=200, style="ButtonNotebook")
|
||||
nb.pressed_index = None
|
||||
f1 = Tkinter.Frame(nb, background="red")
|
||||
f2 = Tkinter.Frame(nb, background="green")
|
||||
f3 = Tkinter.Frame(nb, background="blue")
|
||||
nb.add(f1, text='Red', padding=3)
|
||||
nb.add(f2, text='Green', padding=3)
|
||||
nb.add(f3, text='Blue', padding=3)
|
||||
nb.pack(expand=1, fill='both')
|
||||
|
||||
root.mainloop()
|
||||
269
Demo/tkinter/ttk/plastik_theme.py
Normal file
269
Demo/tkinter/ttk/plastik_theme.py
Normal file
@@ -0,0 +1,269 @@
|
||||
"""This demonstrates good part of the syntax accepted by theme_create.
|
||||
|
||||
This is a translation of plastik.tcl to python.
|
||||
You will need the images used by the plastik theme to test this. The
|
||||
images (and other tile themes) can be retrived by doing:
|
||||
|
||||
$ cvs -z3 -d:pserver:anonymous@tktable.cvs.sourceforge.net:/cvsroot/tktable \
|
||||
co tile-themes
|
||||
|
||||
To test this module you should do, for example:
|
||||
|
||||
import Tkinter
|
||||
import plastik_theme
|
||||
|
||||
root = Tkinter.Tk()
|
||||
plastik_theme.install(plastik_image_dir)
|
||||
...
|
||||
|
||||
Where plastik_image_dir contains the path to the images directory used by
|
||||
the plastik theme, something like: tile-themes/plastik/plastik
|
||||
"""
|
||||
import os
|
||||
import glob
|
||||
import ttk
|
||||
from Tkinter import PhotoImage
|
||||
|
||||
__all__ = ['install']
|
||||
|
||||
colors = {
|
||||
"frame": "#efefef",
|
||||
"disabledfg": "#aaaaaa",
|
||||
"selectbg": "#657a9e",
|
||||
"selectfg": "#ffffff"
|
||||
}
|
||||
|
||||
imgs = {}
|
||||
def _load_imgs(imgdir):
|
||||
imgdir = os.path.expanduser(imgdir)
|
||||
if not os.path.isdir(imgdir):
|
||||
raise Exception("%r is not a directory, can't load images" % imgdir)
|
||||
for f in glob.glob("%s/*.gif" % imgdir):
|
||||
img = os.path.split(f)[1]
|
||||
name = img[:-4]
|
||||
imgs[name] = PhotoImage(name, file=f, format="gif89")
|
||||
|
||||
def install(imgdir):
|
||||
_load_imgs(imgdir)
|
||||
style = ttk.Style()
|
||||
style.theme_create("plastik", "default", settings={
|
||||
".": {
|
||||
"configure":
|
||||
{"background": colors['frame'],
|
||||
"troughcolor": colors['frame'],
|
||||
"selectbackground": colors['selectbg'],
|
||||
"selectforeground": colors['selectfg'],
|
||||
"fieldbackground": colors['frame'],
|
||||
"font": "TkDefaultFont",
|
||||
"borderwidth": 1},
|
||||
"map": {"foreground": [("disabled", colors['disabledfg'])]}
|
||||
},
|
||||
|
||||
"Vertical.TScrollbar": {"layout": [
|
||||
("Vertical.Scrollbar.uparrow", {"side": "top", "sticky": ''}),
|
||||
("Vertical.Scrollbar.downarrow", {"side": "bottom", "sticky": ''}),
|
||||
("Vertical.Scrollbar.uparrow", {"side": "bottom", "sticky": ''}),
|
||||
("Vertical.Scrollbar.trough", {"sticky": "ns", "children":
|
||||
[("Vertical.Scrollbar.thumb", {"expand": 1, "unit": 1,
|
||||
"children": [("Vertical.Scrollbar.grip", {"sticky": ''})]
|
||||
})]
|
||||
})]
|
||||
},
|
||||
|
||||
"Horizontal.TScrollbar": {"layout": [
|
||||
("Horizontal.Scrollbar.leftarrow", {"side": "left", "sticky": ''}),
|
||||
("Horizontal.Scrollbar.rightarrow",
|
||||
{"side": "right", "sticky": ''}),
|
||||
("Horizontal.Scrollbar.leftarrow",
|
||||
{"side": "right", "sticky": ''}),
|
||||
("Horizontal.Scrollbar.trough", {"sticky": "ew", "children":
|
||||
[("Horizontal.Scrollbar.thumb", {"expand": 1, "unit": 1,
|
||||
"children": [("Horizontal.Scrollbar.grip", {"sticky": ''})]
|
||||
})]
|
||||
})]
|
||||
},
|
||||
|
||||
"TButton": {
|
||||
"configure": {"width": 10, "anchor": "center"},
|
||||
"layout": [
|
||||
("Button.button", {"children":
|
||||
[("Button.focus", {"children":
|
||||
[("Button.padding", {"children":
|
||||
[("Button.label", {"side": "left", "expand": 1})]
|
||||
})]
|
||||
})]
|
||||
})
|
||||
]
|
||||
},
|
||||
|
||||
"Toolbutton": {
|
||||
"configure": {"anchor": "center"},
|
||||
"layout": [
|
||||
("Toolbutton.border", {"children":
|
||||
[("Toolbutton.button", {"children":
|
||||
[("Toolbutton.padding", {"children":
|
||||
[("Toolbutton.label", {"side":"left", "expand":1})]
|
||||
})]
|
||||
})]
|
||||
})
|
||||
]
|
||||
},
|
||||
|
||||
"TMenubutton": {"layout": [
|
||||
("Menubutton.button", {"children":
|
||||
[("Menubutton.indicator", {"side": "right"}),
|
||||
("Menubutton.focus", {"children":
|
||||
[("Menubutton.padding", {"children":
|
||||
[("Menubutton.label", {"side": "left", "expand": 1})]
|
||||
})]
|
||||
})]
|
||||
})]
|
||||
},
|
||||
|
||||
"TNotebook": {"configure": {"tabmargins": [0, 2, 0, 0]}},
|
||||
"TNotebook.tab": {
|
||||
"configure": {"padding": [6, 2, 6, 2], "expand": [0, 0, 2]},
|
||||
"map": {"expand": [("selected", [1, 2, 4, 2])]}
|
||||
},
|
||||
"Treeview": {"configure": {"padding": 0}},
|
||||
|
||||
# elements
|
||||
"Button.button": {"element create":
|
||||
("image", 'button-n',
|
||||
("pressed", 'button-p'), ("active", 'button-h'),
|
||||
{"border": [4, 10], "padding": 4, "sticky":"ewns"}
|
||||
)
|
||||
},
|
||||
|
||||
"Toolbutton.button": {"element create":
|
||||
("image", 'tbutton-n',
|
||||
("selected", 'tbutton-p'), ("pressed", 'tbutton-p'),
|
||||
("active", 'tbutton-h'),
|
||||
{"border": [4, 9], "padding": 3, "sticky": "news"}
|
||||
)
|
||||
},
|
||||
|
||||
"Checkbutton.indicator": {"element create":
|
||||
("image", 'check-nu',
|
||||
('active', 'selected', 'check-hc'),
|
||||
('pressed', 'selected', 'check-pc'),
|
||||
('active', 'check-hu'),
|
||||
("selected", 'check-nc'),
|
||||
{"sticky": ''}
|
||||
)
|
||||
},
|
||||
|
||||
"Radiobutton.indicator": {"element create":
|
||||
("image", 'radio-nu',
|
||||
('active', 'selected', 'radio-hc'),
|
||||
('pressed', 'selected', 'radio-pc'),
|
||||
('active', 'radio-hu'), ('selected', 'radio-nc'),
|
||||
{"sticky": ''}
|
||||
)
|
||||
},
|
||||
|
||||
"Horizontal.Scrollbar.thumb": {"element create":
|
||||
("image", 'hsb-n', {"border": 3, "sticky": "ew"})
|
||||
},
|
||||
|
||||
"Horizontal.Scrollbar.grip": {"element create": ("image", 'hsb-g')},
|
||||
"Horizontal.Scrollbar.trough": {"element create": ("image", 'hsb-t')},
|
||||
"Vertical.Scrollbar.thumb": {"element create":
|
||||
("image", 'vsb-n', {"border": 3, "sticky": "ns"})
|
||||
},
|
||||
"Vertical.Scrollbar.grip": {"element create": ("image", 'vsb-g')},
|
||||
"Vertical.Scrollbar.trough": {"element create": ("image", 'vsb-t')},
|
||||
"Scrollbar.uparrow": {"element create":
|
||||
("image", 'arrowup-n', ("pressed", 'arrowup-p'), {"sticky": ''})
|
||||
},
|
||||
"Scrollbar.downarrow": {"element create":
|
||||
("image", 'arrowdown-n',
|
||||
("pressed", 'arrowdown-p'), {'sticky': ''})
|
||||
},
|
||||
"Scrollbar.leftarrow": {"element create":
|
||||
("image", 'arrowleft-n',
|
||||
("pressed", 'arrowleft-p'), {'sticky': ''})
|
||||
},
|
||||
"Scrollbar.rightarrow": {"element create":
|
||||
("image", 'arrowright-n', ("pressed", 'arrowright-p'),
|
||||
{'sticky': ''})
|
||||
},
|
||||
|
||||
"Horizontal.Scale.slider": {"element create":
|
||||
("image", 'hslider-n', {'sticky': ''})
|
||||
},
|
||||
"Horizontal.Scale.trough": {"element create":
|
||||
("image", 'hslider-t', {'border': 1, 'padding': 0})
|
||||
},
|
||||
"Vertical.Scale.slider": {"element create":
|
||||
("image", 'vslider-n', {'sticky': ''})
|
||||
},
|
||||
"Vertical.Scale.trough": {"element create":
|
||||
("image", 'vslider-t', {'border': 1, 'padding': 0})
|
||||
},
|
||||
|
||||
"Entry.field": {"element create":
|
||||
("image", 'entry-n',
|
||||
("focus", 'entry-f'),
|
||||
{'border': 2, 'padding': [3, 4], 'sticky': 'news'}
|
||||
)
|
||||
},
|
||||
|
||||
"Labelframe.border": {"element create":
|
||||
("image", 'border', {'border': 4, 'padding': 4, 'sticky': 'news'})
|
||||
},
|
||||
|
||||
"Menubutton.button": {"element create":
|
||||
("image", 'combo-r',
|
||||
('active', 'combo-ra'),
|
||||
{'sticky': 'news', 'border': [4, 6, 24, 15],
|
||||
'padding': [4, 4, 5]}
|
||||
)
|
||||
},
|
||||
"Menubutton.indicator": {"element create":
|
||||
("image", 'arrow-d', {"sticky": "e", "border": [15, 0, 0, 0]})
|
||||
},
|
||||
|
||||
"Combobox.field": {"element create":
|
||||
("image", 'combo-n',
|
||||
('readonly', 'active', 'combo-ra'),
|
||||
('focus', 'active', 'combo-fa'),
|
||||
('active', 'combo-a'), ('!readonly', 'focus', 'combo-f'),
|
||||
('readonly', 'combo-r'),
|
||||
{'border': [4, 6, 24, 15], 'padding': [4, 4, 5],
|
||||
'sticky': 'news'}
|
||||
)
|
||||
},
|
||||
"Combobox.downarrow": {"element create":
|
||||
("image", 'arrow-d', {'sticky': 'e', 'border': [15, 0, 0, 0]})
|
||||
},
|
||||
|
||||
"Notebook.client": {"element create":
|
||||
("image", 'notebook-c', {'border': 4})
|
||||
},
|
||||
"Notebook.tab": {"element create":
|
||||
("image", 'notebook-tn',
|
||||
("selected", 'notebook-ts'), ("active", 'notebook-ta'),
|
||||
{'padding': [0, 2, 0, 0], 'border': [4, 10, 4, 10]}
|
||||
)
|
||||
},
|
||||
|
||||
"Progressbar.trough": {"element create":
|
||||
("image", 'hprogress-t', {'border': 2})
|
||||
},
|
||||
"Horizontal.Progressbar.pbar": {"element create":
|
||||
("image", 'hprogress-b', {'border': [2, 9]})
|
||||
},
|
||||
"Vertical.Progressbar.pbar": {"element create":
|
||||
("image", 'vprogress-b', {'border': [9, 2]})
|
||||
},
|
||||
|
||||
"Treeheading.cell": {"element create":
|
||||
("image", 'tree-n',
|
||||
("pressed", 'tree-p'),
|
||||
{'border': [4, 10], 'padding': 4, 'sticky': 'news'}
|
||||
)
|
||||
}
|
||||
|
||||
})
|
||||
style.theme_use("plastik")
|
||||
111
Demo/tkinter/ttk/roundframe.py
Normal file
111
Demo/tkinter/ttk/roundframe.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""Ttk Frame with rounded corners.
|
||||
|
||||
Based on an example by Bryan Oakley, found at: http://wiki.tcl.tk/20152"""
|
||||
import Tkinter
|
||||
import ttk
|
||||
|
||||
root = Tkinter.Tk()
|
||||
|
||||
img1 = Tkinter.PhotoImage("frameFocusBorder", data="""
|
||||
R0lGODlhQABAAPcAAHx+fMTCxKSipOTi5JSSlNTS1LSytPTy9IyKjMzKzKyq
|
||||
rOzq7JyanNza3Ly6vPz6/ISChMTGxKSmpOTm5JSWlNTW1LS2tPT29IyOjMzO
|
||||
zKyurOzu7JyenNze3Ly+vPz+/OkAKOUA5IEAEnwAAACuQACUAAFBAAB+AFYd
|
||||
QAC0AABBAAB+AIjMAuEEABINAAAAAHMgAQAAAAAAAAAAAKjSxOIEJBIIpQAA
|
||||
sRgBMO4AAJAAAHwCAHAAAAUAAJEAAHwAAP+eEP8CZ/8Aif8AAG0BDAUAAJEA
|
||||
AHwAAIXYAOfxAIESAHwAAABAMQAbMBZGMAAAIEggJQMAIAAAAAAAfqgaXESI
|
||||
5BdBEgB+AGgALGEAABYAAAAAAACsNwAEAAAMLwAAAH61MQBIAABCM8B+AAAU
|
||||
AAAAAAAApQAAsf8Brv8AlP8AQf8Afv8AzP8A1P8AQf8AfgAArAAABAAADAAA
|
||||
AACQDADjAAASAAAAAACAAADVABZBAAB+ALjMwOIEhxINUAAAANIgAOYAAIEA
|
||||
AHwAAGjSAGEEABYIAAAAAEoBB+MAAIEAAHwCACABAJsAAFAAAAAAAGjJAGGL
|
||||
AAFBFgB+AGmIAAAQAABHAAB+APQoAOE/ABIAAAAAAADQAADjAAASAAAAAPiF
|
||||
APcrABKDAAB8ABgAGO4AAJAAqXwAAHAAAAUAAJEAAHwAAP8AAP8AAP8AAP8A
|
||||
AG0pIwW3AJGSAHx8AEocI/QAAICpAHwAAAA0SABk6xaDEgB8AAD//wD//wD/
|
||||
/wD//2gAAGEAABYAAAAAAAC0/AHj5AASEgAAAAA01gBkWACDTAB8AFf43PT3
|
||||
5IASEnwAAOAYd+PuMBKQTwB8AGgAEGG35RaSEgB8AOj/NOL/ZBL/gwD/fMkc
|
||||
q4sA5UGpEn4AAIg02xBk/0eD/358fx/4iADk5QASEgAAAALnHABkAACDqQB8
|
||||
AMyINARkZA2DgwB8fBABHL0AAEUAqQAAAIAxKOMAPxIwAAAAAIScAOPxABIS
|
||||
AAAAAIIAnQwA/0IAR3cAACwAAAAAQABAAAAI/wA/CBxIsKDBgwgTKlzIsKFD
|
||||
gxceNnxAsaLFixgzUrzAsWPFCw8kDgy5EeQDkBxPolypsmXKlx1hXnS48UEH
|
||||
CwooMCDAgIJOCjx99gz6k+jQnkWR9lRgYYDJkAk/DlAgIMICZlizat3KtatX
|
||||
rAsiCNDgtCJClQkoFMgqsu3ArBkoZDgA8uDJAwk4bGDmtm9BZgcYzK078m4D
|
||||
Cgf4+l0skNkGCg3oUhR4d4GCDIoZM2ZWQMECyZQvLMggIbPmzQIyfCZ5YcME
|
||||
AwFMn/bLLIKBCRtMHljQQcDV2ZqZTRDQYfWFAwMqUJANvC8zBhUWbDi5YUAB
|
||||
Bsybt2VGoUKH3AcmdP+Im127xOcJih+oXsEDdvOLuQfIMGBD9QwBlsOnzcBD
|
||||
hfrsuVfefgzJR599A+CnH4Hb9fcfgu29x6BIBgKYYH4DTojQc/5ZGGGGGhpU
|
||||
IYIKghgiQRw+GKCEJxZIwXwWlthiQyl6KOCMLsJIIoY4LlQjhDf2mNCI9/Eo
|
||||
5IYO2sjikX+9eGCRCzL5V5JALillY07GaOSVb1G5ookzEnlhlFx+8OOXZb6V
|
||||
5Y5kcnlmckGmKaaMaZrpJZxWXjnnlmW++WGdZq5ZXQEetKmnlxPgl6eUYhJq
|
||||
KKOI0imnoNbF2ScFHQJJwW99TsBAAAVYWEAAHEQAZoi1cQDqAAeEV0EACpT/
|
||||
JqcACgRQAW6uNWCbYKcyyEwGDBgQwa2tTlBBAhYIQMFejC5AgQAWJNDABK3y
|
||||
loEDEjCgV6/aOcYBAwp4kIF6rVkXgAEc8IQZVifCBRQHGqya23HGIpsTBgSU
|
||||
OsFX/PbrVVjpYsCABA4kQCxHu11ogAQUIOAwATpBLDFQFE9sccUYS0wAxD5h
|
||||
4DACFEggbAHk3jVBA/gtTIHHEADg8sswxyzzzDQDAAEECGAQsgHiTisZResN
|
||||
gLIHBijwLQEYePzx0kw37fTSSjuMr7ZMzfcgYZUZi58DGsTKwbdgayt22GSP
|
||||
bXbYY3MggQIaONDzAJ8R9kFlQheQQAAOWGCAARrwdt23Bn8H7vfggBMueOEG
|
||||
WOBBAAkU0EB9oBGUdXIFZJBABAEEsPjmmnfO+eeeh/55BBEk0Ph/E8Q9meQq
|
||||
bbDABAN00EADFRRQ++2254777rr3jrvjFTTQwQCpz7u6QRut5/oEzA/g/PPQ
|
||||
Ry/99NIz//oGrZpUUEAAOw==""")
|
||||
|
||||
img2 = Tkinter.PhotoImage("frameBorder", data="""
|
||||
R0lGODlhQABAAPcAAHx+fMTCxKSipOTi5JSSlNTS1LSytPTy9IyKjMzKzKyq
|
||||
rOzq7JyanNza3Ly6vPz6/ISChMTGxKSmpOTm5JSWlNTW1LS2tPT29IyOjMzO
|
||||
zKyurOzu7JyenNze3Ly+vPz+/OkAKOUA5IEAEnwAAACuQACUAAFBAAB+AFYd
|
||||
QAC0AABBAAB+AIjMAuEEABINAAAAAHMgAQAAAAAAAAAAAKjSxOIEJBIIpQAA
|
||||
sRgBMO4AAJAAAHwCAHAAAAUAAJEAAHwAAP+eEP8CZ/8Aif8AAG0BDAUAAJEA
|
||||
AHwAAIXYAOfxAIESAHwAAABAMQAbMBZGMAAAIEggJQMAIAAAAAAAfqgaXESI
|
||||
5BdBEgB+AGgALGEAABYAAAAAAACsNwAEAAAMLwAAAH61MQBIAABCM8B+AAAU
|
||||
AAAAAAAApQAAsf8Brv8AlP8AQf8Afv8AzP8A1P8AQf8AfgAArAAABAAADAAA
|
||||
AACQDADjAAASAAAAAACAAADVABZBAAB+ALjMwOIEhxINUAAAANIgAOYAAIEA
|
||||
AHwAAGjSAGEEABYIAAAAAEoBB+MAAIEAAHwCACABAJsAAFAAAAAAAGjJAGGL
|
||||
AAFBFgB+AGmIAAAQAABHAAB+APQoAOE/ABIAAAAAAADQAADjAAASAAAAAPiF
|
||||
APcrABKDAAB8ABgAGO4AAJAAqXwAAHAAAAUAAJEAAHwAAP8AAP8AAP8AAP8A
|
||||
AG0pIwW3AJGSAHx8AEocI/QAAICpAHwAAAA0SABk6xaDEgB8AAD//wD//wD/
|
||||
/wD//2gAAGEAABYAAAAAAAC0/AHj5AASEgAAAAA01gBkWACDTAB8AFf43PT3
|
||||
5IASEnwAAOAYd+PuMBKQTwB8AGgAEGG35RaSEgB8AOj/NOL/ZBL/gwD/fMkc
|
||||
q4sA5UGpEn4AAIg02xBk/0eD/358fx/4iADk5QASEgAAAALnHABkAACDqQB8
|
||||
AMyINARkZA2DgwB8fBABHL0AAEUAqQAAAIAxKOMAPxIwAAAAAIScAOPxABIS
|
||||
AAAAAIIAnQwA/0IAR3cAACwAAAAAQABAAAAI/wA/CBxIsKDBgwgTKlzIsKFD
|
||||
gxceNnxAsaLFixgzUrzAsWPFCw8kDgy5EeQDkBxPolypsmXKlx1hXnS48UEH
|
||||
CwooMCDAgIJOCjx99gz6k+jQnkWR9lRgYYDJkAk/DlAgIMICkVgHLoggQIPT
|
||||
ighVJqBQIKvZghkoZDgA8uDJAwk4bDhLd+ABBmvbjnzbgMKBuoA/bKDQgC1F
|
||||
gW8XKMgQOHABBQsMI76wIIOExo0FZIhM8sKGCQYCYA4cwcCEDSYPLOgg4Oro
|
||||
uhMEdOB84cCAChReB2ZQYcGGkxsGFGCgGzCFCh1QH5jQIW3xugwSzD4QvIIH
|
||||
4s/PUgiQYcCG4BkC5P/ObpaBhwreq18nb3Z79+8Dwo9nL9I8evjWsdOX6D59
|
||||
fPH71Xeef/kFyB93/sln4EP2Ebjegg31B5+CEDLUIH4PVqiQhOABqKFCF6qn
|
||||
34cHcfjffCQaFOJtGaZYkIkUuljQigXK+CKCE3po40A0trgjjDru+EGPI/6I
|
||||
Y4co7kikkAMBmaSNSzL5gZNSDjkghkXaaGIBHjwpY4gThJeljFt2WSWYMQpZ
|
||||
5pguUnClehS4tuMEDARQgH8FBMBBBExGwIGdAxywXAUBKHCZkAIoEEAFp33W
|
||||
QGl47ZgBAwZEwKigE1SQgAUCUDCXiwtQIIAFCTQwgaCrZeCABAzIleIGHDD/
|
||||
oIAHGUznmXABGMABT4xpmBYBHGgAKGq1ZbppThgAG8EEAW61KwYMSOBAApdy
|
||||
pNp/BkhAAQLcEqCTt+ACJW645I5rLrgEeOsTBtwiQIEElRZg61sTNBBethSw
|
||||
CwEA/Pbr778ABywwABBAgAAG7xpAq6mGUUTdAPZ6YIACsRKAAbvtZqzxxhxn
|
||||
jDG3ybbKFHf36ZVYpuE5oIGhHMTqcqswvyxzzDS/HDMHEiiggQMLDxCZXh8k
|
||||
BnEBCQTggAUGGKCB0ktr0PTTTEfttNRQT22ABR4EkEABDXgnGUEn31ZABglE
|
||||
EEAAWaeN9tpqt832221HEEECW6M3wc+Hga3SBgtMODBABw00UEEBgxdO+OGG
|
||||
J4744oZzXUEDHQxwN7F5G7QRdXxPoPkAnHfu+eeghw665n1vIKhJBQUEADs=""")
|
||||
|
||||
style = ttk.Style()
|
||||
|
||||
style.element_create("RoundedFrame", "image", "frameBorder",
|
||||
("focus", "frameFocusBorder"), border=16, sticky="nsew")
|
||||
|
||||
style.layout("RoundedFrame", [("RoundedFrame", {"sticky": "nsew"})])
|
||||
style.configure("TEntry", borderwidth=0)
|
||||
|
||||
frame = ttk.Frame(style="RoundedFrame", padding=10)
|
||||
frame.pack(fill='x')
|
||||
|
||||
frame2 = ttk.Frame(style="RoundedFrame", padding=10)
|
||||
frame2.pack(fill='both', expand=1)
|
||||
|
||||
entry = ttk.Entry(frame, text='Test')
|
||||
entry.pack(fill='x')
|
||||
entry.bind("<FocusIn>", lambda evt: frame.state(["focus"]))
|
||||
entry.bind("<FocusOut>", lambda evt: frame.state(["!focus"]))
|
||||
|
||||
text = Tkinter.Text(frame2, borderwidth=0, bg="white", highlightthickness=0)
|
||||
text.pack(fill='both', expand=1)
|
||||
text.bind("<FocusIn>", lambda evt: frame2.state(["focus"]))
|
||||
text.bind("<FocusOut>", lambda evt: frame2.state(["!focus"]))
|
||||
|
||||
root.mainloop()
|
||||
61
Demo/tkinter/ttk/theme_selector.py
Normal file
61
Demo/tkinter/ttk/theme_selector.py
Normal file
@@ -0,0 +1,61 @@
|
||||
"""Ttk Theme Selector v2.
|
||||
|
||||
This is an improvement from the other theme selector (themes_combo.py)
|
||||
since now you can notice theme changes in Ttk Combobox, Ttk Frame,
|
||||
Ttk Label and Ttk Button.
|
||||
"""
|
||||
import Tkinter
|
||||
import ttk
|
||||
|
||||
class App(ttk.Frame):
|
||||
def __init__(self):
|
||||
ttk.Frame.__init__(self, borderwidth=3)
|
||||
|
||||
self.style = ttk.Style()
|
||||
|
||||
# XXX Ideally I wouldn't want to create a Tkinter.IntVar to make
|
||||
# it works with Checkbutton variable option.
|
||||
self.theme_autochange = Tkinter.IntVar(self, 0)
|
||||
self._setup_widgets()
|
||||
|
||||
def _change_theme(self):
|
||||
self.style.theme_use(self.themes_combo.get())
|
||||
|
||||
def _theme_sel_changed(self, widget):
|
||||
if self.theme_autochange.get():
|
||||
self._change_theme()
|
||||
|
||||
def _setup_widgets(self):
|
||||
themes_lbl = ttk.Label(self, text="Themes")
|
||||
|
||||
themes = self.style.theme_names()
|
||||
self.themes_combo = ttk.Combobox(self, values=themes, state="readonly")
|
||||
self.themes_combo.set(themes[0])
|
||||
self.themes_combo.bind("<<ComboboxSelected>>", self._theme_sel_changed)
|
||||
|
||||
change_btn = ttk.Button(self, text='Change Theme',
|
||||
command=self._change_theme)
|
||||
|
||||
theme_change_checkbtn = ttk.Checkbutton(self,
|
||||
text="Change themes when combobox item is activated",
|
||||
variable=self.theme_autochange)
|
||||
|
||||
themes_lbl.grid(ipadx=6, sticky="w")
|
||||
self.themes_combo.grid(row=0, column=1, padx=6, sticky="ew")
|
||||
change_btn.grid(row=0, column=2, padx=6, sticky="e")
|
||||
theme_change_checkbtn.grid(row=1, columnspan=3, sticky="w", pady=6)
|
||||
|
||||
top = self.winfo_toplevel()
|
||||
top.rowconfigure(0, weight=1)
|
||||
top.columnconfigure(0, weight=1)
|
||||
self.columnconfigure(1, weight=1)
|
||||
self.grid(row=0, column=0, sticky="nsew", columnspan=3, rowspan=2)
|
||||
|
||||
|
||||
def main():
|
||||
app = App()
|
||||
app.master.title("Theme Selector")
|
||||
app.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
107
Demo/tkinter/ttk/treeview_multicolumn.py
Normal file
107
Demo/tkinter/ttk/treeview_multicolumn.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""Demo based on the demo mclist included with tk source distribution."""
|
||||
import Tkinter
|
||||
import tkFont
|
||||
import ttk
|
||||
|
||||
tree_columns = ("country", "capital", "currency")
|
||||
tree_data = [
|
||||
("Argentina", "Buenos Aires", "ARS"),
|
||||
("Australia", "Canberra", "AUD"),
|
||||
("Brazil", "Brazilia", "BRL"),
|
||||
("Canada", "Ottawa", "CAD"),
|
||||
("China", "Beijing", "CNY"),
|
||||
("France", "Paris", "EUR"),
|
||||
("Germany", "Berlin", "EUR"),
|
||||
("India", "New Delhi", "INR"),
|
||||
("Italy", "Rome", "EUR"),
|
||||
("Japan", "Tokyo", "JPY"),
|
||||
("Mexico", "Mexico City", "MXN"),
|
||||
("Russia", "Moscow", "RUB"),
|
||||
("South Africa", "Pretoria", "ZAR"),
|
||||
("United Kingdom", "London", "GBP"),
|
||||
("United States", "Washington, D.C.", "USD")
|
||||
]
|
||||
|
||||
def sortby(tree, col, descending):
|
||||
"""Sort tree contents when a column is clicked on."""
|
||||
# grab values to sort
|
||||
data = [(tree.set(child, col), child) for child in tree.get_children('')]
|
||||
|
||||
# reorder data
|
||||
data.sort(reverse=descending)
|
||||
for indx, item in enumerate(data):
|
||||
tree.move(item[1], '', indx)
|
||||
|
||||
# switch the heading so that it will sort in the opposite direction
|
||||
tree.heading(col,
|
||||
command=lambda col=col: sortby(tree, col, int(not descending)))
|
||||
|
||||
class App(object):
|
||||
def __init__(self):
|
||||
self.tree = None
|
||||
self._setup_widgets()
|
||||
self._build_tree()
|
||||
|
||||
def _setup_widgets(self):
|
||||
msg = ttk.Label(wraplength="4i", justify="left", anchor="n",
|
||||
padding=(10, 2, 10, 6),
|
||||
text=("Ttk is the new Tk themed widget set. One of the widgets it "
|
||||
"includes is a tree widget, which can be configured to "
|
||||
"display multiple columns of informational data without "
|
||||
"displaying the tree itself. This is a simple way to build "
|
||||
"a listbox that has multiple columns. Clicking on the "
|
||||
"heading for a column will sort the data by that column. "
|
||||
"You can also change the width of the columns by dragging "
|
||||
"the boundary between them."))
|
||||
msg.pack(fill='x')
|
||||
|
||||
container = ttk.Frame()
|
||||
container.pack(fill='both', expand=True)
|
||||
|
||||
# XXX Sounds like a good support class would be one for constructing
|
||||
# a treeview with scrollbars.
|
||||
self.tree = ttk.Treeview(columns=tree_columns, show="headings")
|
||||
vsb = ttk.Scrollbar(orient="vertical", command=self.tree.yview)
|
||||
hsb = ttk.Scrollbar(orient="horizontal", command=self.tree.xview)
|
||||
self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
|
||||
self.tree.grid(column=0, row=0, sticky='nsew', in_=container)
|
||||
vsb.grid(column=1, row=0, sticky='ns', in_=container)
|
||||
hsb.grid(column=0, row=1, sticky='ew', in_=container)
|
||||
|
||||
container.grid_columnconfigure(0, weight=1)
|
||||
container.grid_rowconfigure(0, weight=1)
|
||||
|
||||
def _build_tree(self):
|
||||
for col in tree_columns:
|
||||
self.tree.heading(col, text=col.title(),
|
||||
command=lambda c=col: sortby(self.tree, c, 0))
|
||||
# XXX tkFont.Font().measure expected args are incorrect according
|
||||
# to the Tk docs
|
||||
self.tree.column(col, width=tkFont.Font().measure(col.title()))
|
||||
|
||||
for item in tree_data:
|
||||
self.tree.insert('', 'end', values=item)
|
||||
|
||||
# adjust columns lenghts if necessary
|
||||
for indx, val in enumerate(item):
|
||||
ilen = tkFont.Font().measure(val)
|
||||
if self.tree.column(tree_columns[indx], width=None) < ilen:
|
||||
self.tree.column(tree_columns[indx], width=ilen)
|
||||
|
||||
def main():
|
||||
root = Tkinter.Tk()
|
||||
root.wm_title("Multi-Column List")
|
||||
root.wm_iconname("mclist")
|
||||
|
||||
import plastik_theme
|
||||
try:
|
||||
plastik_theme.install('~/tile-themes/plastik/plastik')
|
||||
except Exception:
|
||||
import warnings
|
||||
warnings.warn("plastik theme being used without images")
|
||||
|
||||
app = App()
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
231
Demo/tkinter/ttk/ttkcalendar.py
Normal file
231
Demo/tkinter/ttk/ttkcalendar.py
Normal file
@@ -0,0 +1,231 @@
|
||||
"""
|
||||
Simple calendar using ttk Treeview together with calendar and datetime
|
||||
classes.
|
||||
"""
|
||||
import calendar
|
||||
import Tkinter
|
||||
import tkFont
|
||||
import ttk
|
||||
|
||||
def get_calendar(locale, fwday):
|
||||
# instantiate proper calendar class
|
||||
if locale is None:
|
||||
return calendar.TextCalendar(fwday)
|
||||
else:
|
||||
return calendar.LocaleTextCalendar(fwday, locale)
|
||||
|
||||
class Calendar(ttk.Frame):
|
||||
# XXX ToDo: cget and configure
|
||||
|
||||
datetime = calendar.datetime.datetime
|
||||
timedelta = calendar.datetime.timedelta
|
||||
|
||||
def __init__(self, master=None, **kw):
|
||||
"""
|
||||
WIDGET-SPECIFIC OPTIONS
|
||||
|
||||
locale, firstweekday, year, month, selectbackground,
|
||||
selectforeground
|
||||
"""
|
||||
# remove custom options from kw before initializating ttk.Frame
|
||||
fwday = kw.pop('firstweekday', calendar.MONDAY)
|
||||
year = kw.pop('year', self.datetime.now().year)
|
||||
month = kw.pop('month', self.datetime.now().month)
|
||||
locale = kw.pop('locale', None)
|
||||
sel_bg = kw.pop('selectbackground', '#ecffc4')
|
||||
sel_fg = kw.pop('selectforeground', '#05640e')
|
||||
|
||||
self._date = self.datetime(year, month, 1)
|
||||
self._selection = None # no date selected
|
||||
|
||||
ttk.Frame.__init__(self, master, **kw)
|
||||
|
||||
self._cal = get_calendar(locale, fwday)
|
||||
|
||||
self.__setup_styles() # creates custom styles
|
||||
self.__place_widgets() # pack/grid used widgets
|
||||
self.__config_calendar() # adjust calendar columns and setup tags
|
||||
# configure a canvas, and proper bindings, for selecting dates
|
||||
self.__setup_selection(sel_bg, sel_fg)
|
||||
|
||||
# store items ids, used for insertion later
|
||||
self._items = [self._calendar.insert('', 'end', values='')
|
||||
for _ in range(6)]
|
||||
# insert dates in the currently empty calendar
|
||||
self._build_calendar()
|
||||
|
||||
# set the minimal size for the widget
|
||||
self._calendar.bind('<Map>', self.__minsize)
|
||||
|
||||
def __setitem__(self, item, value):
|
||||
if item in ('year', 'month'):
|
||||
raise AttributeError("attribute '%s' is not writeable" % item)
|
||||
elif item == 'selectbackground':
|
||||
self._canvas['background'] = value
|
||||
elif item == 'selectforeground':
|
||||
self._canvas.itemconfigure(self._canvas.text, item=value)
|
||||
else:
|
||||
ttk.Frame.__setitem__(self, item, value)
|
||||
|
||||
def __getitem__(self, item):
|
||||
if item in ('year', 'month'):
|
||||
return getattr(self._date, item)
|
||||
elif item == 'selectbackground':
|
||||
return self._canvas['background']
|
||||
elif item == 'selectforeground':
|
||||
return self._canvas.itemcget(self._canvas.text, 'fill')
|
||||
else:
|
||||
r = ttk.tclobjs_to_py({item: ttk.Frame.__getitem__(self, item)})
|
||||
return r[item]
|
||||
|
||||
def __setup_styles(self):
|
||||
# custom ttk styles
|
||||
style = ttk.Style(self.master)
|
||||
arrow_layout = lambda dir: (
|
||||
[('Button.focus', {'children': [('Button.%sarrow' % dir, None)]})]
|
||||
)
|
||||
style.layout('L.TButton', arrow_layout('left'))
|
||||
style.layout('R.TButton', arrow_layout('right'))
|
||||
|
||||
def __place_widgets(self):
|
||||
# header frame and its widgets
|
||||
hframe = ttk.Frame(self)
|
||||
lbtn = ttk.Button(hframe, style='L.TButton', command=self._prev_month)
|
||||
rbtn = ttk.Button(hframe, style='R.TButton', command=self._next_month)
|
||||
self._header = ttk.Label(hframe, width=15, anchor='center')
|
||||
# the calendar
|
||||
self._calendar = ttk.Treeview(show='', selectmode='none', height=7)
|
||||
|
||||
# pack the widgets
|
||||
hframe.pack(in_=self, side='top', pady=4, anchor='center')
|
||||
lbtn.grid(in_=hframe)
|
||||
self._header.grid(in_=hframe, column=1, row=0, padx=12)
|
||||
rbtn.grid(in_=hframe, column=2, row=0)
|
||||
self._calendar.pack(in_=self, expand=1, fill='both', side='bottom')
|
||||
|
||||
def __config_calendar(self):
|
||||
cols = self._cal.formatweekheader(3).split()
|
||||
self._calendar['columns'] = cols
|
||||
self._calendar.tag_configure('header', background='grey90')
|
||||
self._calendar.insert('', 'end', values=cols, tag='header')
|
||||
# adjust its columns width
|
||||
font = tkFont.Font()
|
||||
maxwidth = max(font.measure(col) for col in cols)
|
||||
for col in cols:
|
||||
self._calendar.column(col, width=maxwidth, minwidth=maxwidth,
|
||||
anchor='e')
|
||||
|
||||
def __setup_selection(self, sel_bg, sel_fg):
|
||||
self._font = tkFont.Font()
|
||||
self._canvas = canvas = Tkinter.Canvas(self._calendar,
|
||||
background=sel_bg, borderwidth=0, highlightthickness=0)
|
||||
canvas.text = canvas.create_text(0, 0, fill=sel_fg, anchor='w')
|
||||
|
||||
canvas.bind('<ButtonPress-1>', lambda evt: canvas.place_forget())
|
||||
self._calendar.bind('<Configure>', lambda evt: canvas.place_forget())
|
||||
self._calendar.bind('<ButtonPress-1>', self._pressed)
|
||||
|
||||
def __minsize(self, evt):
|
||||
width, height = self._calendar.master.geometry().split('x')
|
||||
height = height[:height.index('+')]
|
||||
self._calendar.master.minsize(width, height)
|
||||
|
||||
def _build_calendar(self):
|
||||
year, month = self._date.year, self._date.month
|
||||
|
||||
# update header text (Month, YEAR)
|
||||
header = self._cal.formatmonthname(year, month, 0)
|
||||
self._header['text'] = header.title()
|
||||
|
||||
# update calendar shown dates
|
||||
cal = self._cal.monthdayscalendar(year, month)
|
||||
for indx, item in enumerate(self._items):
|
||||
week = cal[indx] if indx < len(cal) else []
|
||||
fmt_week = [('%02d' % day) if day else '' for day in week]
|
||||
self._calendar.item(item, values=fmt_week)
|
||||
|
||||
def _show_selection(self, text, bbox):
|
||||
"""Configure canvas for a new selection."""
|
||||
x, y, width, height = bbox
|
||||
|
||||
textw = self._font.measure(text)
|
||||
|
||||
canvas = self._canvas
|
||||
canvas.configure(width=width, height=height)
|
||||
canvas.coords(canvas.text, width - textw, height / 2 - 1)
|
||||
canvas.itemconfigure(canvas.text, text=text)
|
||||
canvas.place(in_=self._calendar, x=x, y=y)
|
||||
|
||||
# Callbacks
|
||||
|
||||
def _pressed(self, evt):
|
||||
"""Clicked somewhere in the calendar."""
|
||||
x, y, widget = evt.x, evt.y, evt.widget
|
||||
item = widget.identify_row(y)
|
||||
column = widget.identify_column(x)
|
||||
|
||||
if not column or not item in self._items:
|
||||
# clicked in the weekdays row or just outside the columns
|
||||
return
|
||||
|
||||
item_values = widget.item(item)['values']
|
||||
if not len(item_values): # row is empty for this month
|
||||
return
|
||||
|
||||
text = item_values[int(column[1]) - 1]
|
||||
if not text: # date is empty
|
||||
return
|
||||
|
||||
bbox = widget.bbox(item, column)
|
||||
if not bbox: # calendar not visible yet
|
||||
return
|
||||
|
||||
# update and then show selection
|
||||
text = '%02d' % text
|
||||
self._selection = (text, item, column)
|
||||
self._show_selection(text, bbox)
|
||||
|
||||
def _prev_month(self):
|
||||
"""Updated calendar to show the previous month."""
|
||||
self._canvas.place_forget()
|
||||
|
||||
self._date = self._date - self.timedelta(days=1)
|
||||
self._date = self.datetime(self._date.year, self._date.month, 1)
|
||||
self._build_calendar() # reconstruct calendar
|
||||
|
||||
def _next_month(self):
|
||||
"""Update calendar to show the next month."""
|
||||
self._canvas.place_forget()
|
||||
|
||||
year, month = self._date.year, self._date.month
|
||||
self._date = self._date + self.timedelta(
|
||||
days=calendar.monthrange(year, month)[1] + 1)
|
||||
self._date = self.datetime(self._date.year, self._date.month, 1)
|
||||
self._build_calendar() # reconstruct calendar
|
||||
|
||||
# Properties
|
||||
|
||||
@property
|
||||
def selection(self):
|
||||
"""Return a datetime representing the current selected date."""
|
||||
if not self._selection:
|
||||
return None
|
||||
|
||||
year, month = self._date.year, self._date.month
|
||||
return self.datetime(year, month, int(self._selection[0]))
|
||||
|
||||
def test():
|
||||
import sys
|
||||
root = Tkinter.Tk()
|
||||
root.title('Ttk Calendar')
|
||||
ttkcal = Calendar(firstweekday=calendar.SUNDAY)
|
||||
ttkcal.pack(expand=1, fill='both')
|
||||
|
||||
if 'win' not in sys.platform:
|
||||
style = ttk.Style()
|
||||
style.theme_use('clam')
|
||||
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test()
|
||||
83
Demo/tkinter/ttk/widget_state.py
Normal file
83
Demo/tkinter/ttk/widget_state.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""Sample demo showing widget states and some font styling."""
|
||||
import ttk
|
||||
|
||||
states = ['active', 'disabled', 'focus', 'pressed', 'selected',
|
||||
'background', 'readonly', 'alternate', 'invalid']
|
||||
|
||||
for state in states[:]:
|
||||
states.append("!" + state)
|
||||
|
||||
def reset_state(widget):
|
||||
nostate = states[len(states) // 2:]
|
||||
widget.state(nostate)
|
||||
|
||||
class App(ttk.Frame):
|
||||
def __init__(self, title=None):
|
||||
ttk.Frame.__init__(self, borderwidth=6)
|
||||
self.master.title(title)
|
||||
|
||||
self.style = ttk.Style()
|
||||
|
||||
# get default font size and family
|
||||
btn_font = self.style.lookup("TButton", "font")
|
||||
fsize = str(self.tk.eval("font configure %s -size" % btn_font))
|
||||
self.font_family = self.tk.eval("font configure %s -family" % btn_font)
|
||||
if ' ' in self.font_family:
|
||||
self.font_family = '{%s}' % self.font_family
|
||||
self.fsize_prefix = fsize[0] if fsize[0] == '-' else ''
|
||||
self.base_fsize = int(fsize[1 if fsize[0] == '-' else 0:])
|
||||
|
||||
# a list to hold all the widgets that will have their states changed
|
||||
self.update_widgets = []
|
||||
|
||||
self._setup_widgets()
|
||||
|
||||
def _set_font(self, extra=0):
|
||||
self.style.configure("TButton", font="%s %s%d" % (self.font_family,
|
||||
self.fsize_prefix, self.base_fsize + extra))
|
||||
|
||||
def _new_state(self, widget, newtext):
|
||||
widget = self.nametowidget(widget)
|
||||
|
||||
if not newtext:
|
||||
goodstates = ["disabled"]
|
||||
font_extra = 0
|
||||
else:
|
||||
# set widget state according to what has been entered in the entry
|
||||
newstates = set(newtext.split()) # eliminate duplicates
|
||||
|
||||
# keep only the valid states
|
||||
goodstates = [state for state in newstates if state in states]
|
||||
# define a new font size based on amount of states
|
||||
font_extra = 2 * len(goodstates)
|
||||
|
||||
# set new widget state
|
||||
for widget in self.update_widgets:
|
||||
reset_state(widget) # remove any previous state from the widget
|
||||
widget.state(goodstates)
|
||||
|
||||
# update Ttk Button font size
|
||||
self._set_font(font_extra)
|
||||
return 1
|
||||
|
||||
def _setup_widgets(self):
|
||||
btn = ttk.Button(self, text='Enter states and watch')
|
||||
|
||||
entry = ttk.Entry(self, cursor='xterm', validate="key")
|
||||
entry['validatecommand'] = (self.register(self._new_state), '%W', '%P')
|
||||
entry.focus()
|
||||
|
||||
self.update_widgets.append(btn)
|
||||
entry.validate()
|
||||
|
||||
entry.pack(fill='x', padx=6)
|
||||
btn.pack(side='left', pady=6, padx=6, anchor='n')
|
||||
self.pack(fill='both', expand=1)
|
||||
|
||||
|
||||
def main():
|
||||
app = App("Widget State Tester")
|
||||
app.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user