- scrolled canvas: uses canvas windows with frames and a scrollbar. credit: python source code demo "canvas-with-scrollbars.py"
- treeview table: uses a ttk.Treeview to make a table - and they said it couldn't be done. credit: daniweb
- rascally resize tk scrollbars
- ttk Notebook demo for Py2


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() |
No comments:
Post a Comment