Last active
December 19, 2015 05:49
-
-
Save mikofski/5907350 to your computer and use it in GitHub Desktop.
ttk widgets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from Tkinter import Canvas, GROOVE, BOTH, X, Y, YES, RIGHT, LEFT, W | |
from ttk import Frame, Scrollbar, Checkbutton | |
import logging | |
import tkMessageBox | |
class ScrolledCanvas(Frame): | |
""" | |
A scrolling canvas of frames with checkboxes. | |
""" | |
def __init__(self, master, name=None, scrollregion=(0, 0, '5i', '5i'), | |
items=[], window_size=[160, 30], **canvaskw): | |
Frame.__init__(self, master, name=name) | |
self.scrollcanvas = Canvas(self, name='scrollcanvas', | |
scrollregion=scrollregion, **canvaskw) | |
self.yscroll = Scrollbar(self, name='yscroll', | |
command=self.scrollcanvas.yview) | |
self.scrollcanvas['yscrollcommand'] = self.yscroll.set | |
self.yscroll.pack(side=RIGHT, fill=Y) | |
self.scrollcanvas.pack(side=LEFT, fill=BOTH, expand=YES) | |
self.items = dict.fromkeys(items) | |
for n, i in enumerate(items): | |
self.items[i] = {'frame': Frame(self, name=(i.lower() + '_frame'))} | |
self.items[i]['frame'].config(relief=GROOVE, padding=5) | |
self.items[i]['chbx'] = Checkbutton(self.items[i]['frame'], | |
name=(i.lower() + '_chbx')) | |
self.items[i]['chbx']['text'] = i | |
self.items[i]['chbx'].pack(side=LEFT, fill=X) | |
y = window_size[1] / 2 + window_size[1] * n | |
self.items[i]['window'] = self.scrollcanvas.create_window(0, y) | |
self.scrollcanvas.itemconfigure(self.items[i]['window'], | |
window=self.items[i]['frame'], | |
anchor=W, width=window_size[0], | |
height=window_size[1]) | |
def onLeftClick(item, event): | |
logging.debug(event.__dict__) | |
if tkMessageBox.askokcancel('scrolled canvas', item): | |
return | |
if __name__ == "__main__": | |
import tkFont | |
from Tkinter import Tk | |
dummy_items = ['holy grail', 'meaning of life', 'life of brian', | |
'jabberwocky', "monte python's flying circus", | |
'time bandits', 'brazil', '12 monkeys', | |
'adventures of baron von munchausen'] | |
root = Tk() | |
maxstr = max(dummy_items, key=lambda x: len(x)) | |
pixsz = tkFont.Font().measure(maxstr)+25 | |
chrsz = len(maxstr)+5 | |
scrollcanvas = ScrolledCanvas(root, scrollregion=[0, 0, '5i', '3i'], | |
items=dummy_items, height='2i', | |
window_size=[pixsz, 30], width=pixsz) | |
# add bindings? | |
for item, val in scrollcanvas.items.iteritems(): | |
logging.debug('binding frame %s', val['frame']) | |
callback = lambda e, i=item: onLeftClick(i, e) | |
val['frame'].bind('<Button-1>', callback) | |
scrollcanvas.pack(expand=YES, fill=BOTH) | |
scrollcanvas.mainloop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from Tkinter import N, E, W, S, END, YES, BOTH | |
from ttk import Frame, Treeview, Scrollbar | |
import tkFont | |
import logging | |
class TreeTable(Frame): | |
""" | |
A table based on :class:`ttk.Treeview`. | |
:Parameters: | |
**master** : Tkinter or ttk widget | |
The widget in which the :class:`TableTree` will reside. | |
**headers** : list of str | |
The column headers for the table. | |
**data** : list of tuples | |
Table data. There must be as many elements in each tuple as there \ | |
are headers. Each tuple in the list corresponds to a row in the \ | |
table. | |
""" | |
def __init__(self, master, headers, data, name=None): | |
Frame.__init__(self, master, name=name) | |
#: column headers | |
self.headers = headers | |
#: table data | |
self.data = data | |
#: :class:`~ttk.Treeview` that only shows "headings" not "tree columns" | |
self.tree = Treeview(self, columns=self.headers, show="headings", | |
name='tabletree') | |
#: vertical scrollbar | |
self.yscroll = Scrollbar(self, orient="vertical", | |
command=self.tree.yview, name='table_yscroll') | |
#: horizontal scrollbar | |
self.xscroll = Scrollbar(self, orient="horizontal", | |
command=self.tree.xview, name='table_xscroll') | |
self.tree['yscrollcommand'] = self.yscroll.set # bind to scrollbars | |
self.tree['xscrollcommand'] = self.xscroll.set | |
# position widgets and set resize behavior | |
self.tree.grid(column=0, row=0, sticky=(N + E + W + S)) | |
self.yscroll.grid(column=1, row=0, sticky=(N + S)) | |
self.xscroll.grid(column=0, row=1, sticky=(E + W)) | |
self.grid_columnconfigure(0, weight=1) | |
self.grid_rowconfigure(0, weight=1) | |
# build tree | |
for col in self.headers: | |
# NOTE: Use col as column identifiers, crafty! | |
# NOTE: Also change col to title case using str.title() | |
# NOTE: make lambda behave nicely in a loop using default arg! | |
callback = lambda c=col: self.sortby(c, False) | |
self.tree.heading(col, text=col.title(), command=callback) | |
# adjust the column's width to the header string | |
self.tree.column(col, width=tkFont.Font().measure(col.title())) | |
# insert a new top-level treeview item by suing an empty string | |
for item in self.data: | |
self.tree.insert('', END, values=item) | |
# adjust column's width if necessary to fit each value | |
for idx, val in enumerate(item): | |
col_width = tkFont.Font().measure(val) | |
# option can be specified at least 3 ways: as (a) width=None, | |
# (b) option='width' or (c) 'width', where 'width' can be any | |
# valid column option. | |
if self.tree.column(self.headers[idx], 'width') < col_width: | |
self.tree.column(self.headers[idx], width=col_width) | |
def sortby(self, col, descending): | |
""" | |
Sort table contents when a column header is clicked. | |
:Parameters: | |
**col** | |
The column identifier of the column to sort. | |
**descending** | |
False if ascending, True if descending, switches each time. | |
""" | |
logging.debug('sortby %s, descending: %s', col, descending) | |
# grab values to sort | |
data = [(self.tree.set(child, col), child) | |
for child in self.tree.get_children('')] | |
# now sort the data in place | |
data.sort(reverse=descending) | |
for idx, item in enumerate(data): | |
self.tree.move(item[1], '', idx) | |
# switch the heading so it will sort in the opposite direction | |
callback = lambda: self.sortby(col, not descending) | |
self.tree.heading(col, command=callback) | |
if __name__ == "__main__": | |
from Tkinter import Tk | |
dummy_data = [('holy grail', 1975), ('meaning of life', 1983), | |
('life of brian', 1979), ('jabberwocky', 1977), | |
('time bandits', 1981), ('brazil', 1985), | |
('12 monkeys', 1995), | |
('adventures of baron von munchausen', 1988)] | |
headers = ['movie title', 'year'] | |
root = Tk() | |
treetable = TreeTable(root, headers=headers, data=dummy_data) | |
treetable.tree['height'] = 4 | |
treetable.pack(expand=YES, fill=BOTH) | |
treetable.mainloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment