Advertisement
here2share

# Tk_multicolumn ListBox.py

Jan 8th, 2022
1,319
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.81 KB | None | 0 0
  1. # Tk_multicolumn ListBox.py
  2.  
  3. '''
  4. Here the TreeView widget is configured as a multi-column listbox
  5. with adjustable column width and column-header-click sorting.
  6. '''
  7. try:
  8.     import Tkinter as tk
  9.     import tkFont
  10.     import ttk
  11. except ImportError:  # Python 3
  12.     import tkinter as tk
  13.     import tkinter.font as tkFont
  14.     import tkinter.ttk as ttk
  15.  
  16. class MultiColumnListbox(object):
  17.     """use a ttk.TreeView as a multicolumn ListBox"""
  18.  
  19.     def __init__(self):
  20.         self.tree = None
  21.         self._setup_widgets()
  22.         self._build_tree()
  23.  
  24.     def bind(self, name, func, add=""):
  25.         self.tree.bind(name, func, add)
  26.  
  27.     def _setup_widgets(self):
  28.         s = """Click on header to sort by that column
  29. to change width of column drag boundary
  30.         """
  31.         msg = ttk.Label(wraplength="4i", justify="left", anchor="n",
  32.             padding=(14, 2, 14, 6), text=s)
  33.         msg.pack(fill='x')
  34.         container = ttk.Frame()
  35.         container.pack(fill='both', expand=True)
  36.         # create a treeview with dual scrollbars
  37.         self.tree = ttk.Treeview(columns=zzz_header, show="headings")
  38.         vsb = ttk.Scrollbar(orient="vertical",
  39.             command=self.tree.yview)
  40.         hsb = ttk.Scrollbar(orient="horizontal",
  41.             command=self.tree.xview)
  42.         self.tree.configure(yscrollcommand=vsb.set,
  43.             xscrollcommand=hsb.set)
  44.         self.tree.grid(column=0, row=0, sticky='nsew', in_=container)
  45.         vsb.grid(column=1, row=0, sticky='ns', in_=container)
  46.         hsb.grid(column=0, row=1, sticky='ew', in_=container)
  47.         container.grid_columnconfigure(0, weight=1)
  48.         container.grid_rowconfigure(0, weight=1)
  49.  
  50.     def _build_tree(self):
  51.         for col in zzz_header:
  52.             self.tree.heading(col, text=col.title(),
  53.                 command=lambda c=col: sortby(self.tree, c, 0))
  54.             # adjust the column's width to the header string
  55.             self.tree.column(col,
  56.                 width=tkFont.Font().measure(col.title()))
  57.  
  58.         for item in zzz_list:
  59.             if type(item) is list:
  60.                 _group = self.tree.insert('', 'end', item[0], values=item[0])
  61.                 for subitem in item:
  62.                     self.tree.insert(_group, 'end', values=subitem)
  63.             else:
  64.                 self.tree.insert('', 'end',text=item[0], values=item)
  65.             # adjust column's width if necessary to fit each value
  66.             for ix, val in enumerate(item):
  67.                 col_w = tkFont.Font().measure(val)
  68.                 if self.tree.column(zzz_header[ix],width=None)<col_w:
  69.                     self.tree.column(zzz_header[ix], width=col_w)
  70.  
  71. def sortby(tree, col, descending):
  72.     """sort tree contents when a column header is clicked on"""
  73.     # grab values to sort
  74.     data = [(tree.set(child, col), child) \
  75.         for child in tree.get_children('')]
  76.     # if the data to be sorted is numeric change to float
  77.     #data =  change_numeric(data)
  78.     # now sort the data in place
  79.     data.sort(reverse=descending)
  80.     for ix, item in enumerate(data):
  81.         tree.move(item[1], '', ix)
  82.     # switch the heading so it will sort in the opposite direction
  83.     tree.heading(col, command=lambda col=col: sortby(tree, col, \
  84.         int(not descending)))
  85.  
  86. # the test data ...
  87.  
  88. zzz_header = ['CLICK*','1','2 (Read #3)','3 (Read #4)','4 (Read #1)','5 (Read #2)']
  89. zzz_list = [
  90. ('0', 'See', 'Our', 'Left', 'Become', 'Life'),
  91. ('2', 'People', 'The', 'Those(2)', 'Around', 'Easier'),
  92. ('E', 'In', 'Borrow', 'May', 'Better', 'People'),
  93. ('3', 'See(2)', 'We', 'Who(2)', 'Too', 'And'),
  94. ('B', 'Difficulty', 'Earth', 'Those', 'Everything', 'Good'),
  95. ('D', 'Only', 'We(2)', 'Hustle', 'To', 'Other'),
  96. ('4', 'Every(2)', 'Ancestors', 'Things', 'We(2)', 'More'),
  97. ('A', 'Opportunity', 'From(2)', 'Wait', 'Becomes', 'The'),
  98. ('5', 'Difficulty(2)', 'Do', 'To', 'Us', 'Beautiful'),
  99. ('C', 'Every', 'From', 'Who', 'Better(2)', 'In'),
  100. ('6', 'Whereas', 'Children', 'Come', 'Strive', 'When'),
  101. ('8', 'Opportunity(2)', 'Inherit', 'But', 'When', 'Can'),
  102. ('1', 'Optimistic', 'Not', 'Things(2)', 'Are', 'Becomes'),
  103. ('9', 'Pessimist', 'It', 'Only', 'Than', 'See'),
  104. ('7', 'In(2)', 'Our(2)', 'By', 'We', 'We')]
  105.  
  106. def bDown_Shift(event):
  107.     tv = event.widget
  108.     select = [tv.index(s) for s in tv.selection()]
  109.     select.append(tv.index(tv.identify_row(event.y)))
  110.     select.sort()
  111.     for i in range(select[0],select[-1]+1,1):
  112.         tv.selection_add(tv.get_children()[i])
  113.  
  114. def bDown(event):
  115.     tv = event.widget
  116.     if tv.identify_row(event.y) not in tv.selection():
  117.         tv.selection_set(tv.identify_row(event.y))
  118.  
  119. def bUp(event):
  120.     tv = event.widget
  121.     if tv.identify_row(event.y) in tv.selection():
  122.         tv.selection_set(tv.identify_row(event.y))
  123.  
  124. def bUp_Shift(event):
  125.     pass
  126.  
  127. def bMove(event):
  128.     tv = event.widget
  129.     moveto = tv.index(tv.identify_row(event.y))
  130.     for s in tv.selection():
  131.         tv.move(s, '', moveto)
  132.  
  133.  
  134. if __name__ == '__main__':
  135.  
  136.     root = tk.Tk()
  137.     root.title("Multicolumn Treeview/Listbox")
  138.     listbox = MultiColumnListbox()
  139.     listbox.bind("<ButtonPress-1>",bDown)
  140.     listbox.bind("<ButtonRelease-1>",bUp, add='+')
  141.     listbox.bind("<B1-Motion>",bMove, add='+')
  142.     listbox.bind("<Shift-ButtonPress-1>",bDown_Shift, add='+')
  143.     listbox.bind("<Shift-ButtonRelease-1>",bUp_Shift, add='+')
  144.     root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement