Demos for ttk added.

This commit is contained in:
Guilherme Polo 2009-01-28 15:56:01 +00:00
parent cda93aafde
commit 4eae078448
16 changed files with 1197 additions and 0 deletions

View File

@ -8,3 +8,4 @@ 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

View 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()

View 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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

View 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()

View 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()

View 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()

View 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")

View 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="""
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
Ry/99NIz//oGrZpUUEAAOw==""")
img2 = Tkinter.PhotoImage("frameBorder", data="""
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""")
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()

View 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()

View 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()

View 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() # reconstuct 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()

View 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()

View File

@ -379,6 +379,8 @@ Library
Tools/Demos
-----------
- Ttk demos added in Demo/tkinter/ttk/
- Issue #4677: add two list comprehension tests to pybench.
Build