Advertisement
Uno-Dan

Treeview Windows version

Apr 27th, 2020
655
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.34 KB | None | 0 0
  1.  
  2.     import tkinter as tk
  3.     import tkinter.ttk as ttk
  4.     import tkinter.font as tkfont
  5.    
  6.    
  7.     class App(tk.Tk):
  8.         def __init__(self):
  9.             super().__init__()
  10.    
  11.             def tag_replace(item, old, new):
  12.                 if tv.tag_has(old, item):
  13.                     tags_remove(item, old)
  14.                     tags_add(item, new)
  15.    
  16.             def tags_add(item, tags):
  17.                 if isinstance(tags, str):
  18.                     tags = (tags,)
  19.    
  20.                 _tags = list(tv.item(item)['tags'])
  21.                 _tags = [] if not _tags else _tags
  22.    
  23.                 for _tag in tags:
  24.                     if _tag not in _tags:
  25.                         _tags.append(_tag)
  26.                 tv.item(item, tags=_tags)
  27.    
  28.             def tags_reset(_=None):
  29.                 tags_replace_all('selected_odd', 'odd')
  30.                 tags_replace_all('selected_even', 'even')
  31.    
  32.             def tags_remove(item, tags):
  33.                 if isinstance(tags, str):
  34.                     tags = (tags,)
  35.                 _tags = list(tv.item(item, 'tags'))
  36.    
  37.                 for _tag in tags:
  38.                     if _tag in _tags:
  39.                         _tags.pop(_tags.index(_tag))
  40.                 tv.item(item, tags=_tags)
  41.    
  42.             def tags_remove_all(*tags):
  43.                 def do_remove(node):
  44.                     tags_remove(node, tags)
  45.                     for node in tv.get_children(node):
  46.                         do_remove(node)
  47.    
  48.                 for child in tv.get_children():
  49.                     do_remove(child)
  50.    
  51.             def tags_replace_all(old, new):
  52.                 for item in tv.tag_has(old):
  53.                     tag_replace(item, old, new)
  54.    
  55.             def escape(_):
  56.                 tags_remove_all('selected', '_selected')
  57.                 tags_reset()
  58.    
  59.             def fixed_map(option):
  60.                 return [elm for elm in style.map("Treeview", query_opt=option) if elm[:2] != ("!disabled", "!selected")]
  61.    
  62.             def button_press(event):
  63.                 self.selected = []
  64.                 self.anchor_x, self.anchor_y = event.x, event.y
  65.                 item = self.anchor_item = self.active_item = tv.identify('item', event.x, event.y)
  66.    
  67.                 if not item:
  68.                     return
  69.    
  70.                 if event.state & 1 << 2:
  71.                     tags_add(item, ('selected', ))
  72.                     if tv.tag_has('odd', item):
  73.                         tag_replace(item, 'odd', 'selected_odd')
  74.                     elif tv.tag_has('selected_odd', item):
  75.                         tag_replace(item, 'selected_odd', 'odd')
  76.                     elif tv.tag_has('even', item):
  77.                         tag_replace(item, 'even', 'selected_even')
  78.                     elif tv.tag_has('selected_even', item):
  79.                         tag_replace(item, 'selected_even', 'even')
  80.                 else:
  81.                     tags_remove_all('selected', '_selected')
  82.                     tags_reset()
  83.                     tags_add(item, 'selected')
  84.                     if tv.tag_has('odd', item):
  85.                         tag_replace(item, 'odd', 'selected_odd')
  86.                     elif tv.tag_has('even', item):
  87.                         tag_replace(item, 'even', 'selected_even')
  88.    
  89.                 dw.geometry('0x0+0+0')
  90.                 dw.deiconify()
  91.                 self.bind('<Motion>', selection_window)
  92.    
  93.             def button_release(_):
  94.                 dw.withdraw()
  95.                 self.unbind('<Motion>')
  96.                 tags_replace_all('_selected', 'selected')
  97.    
  98.             def set_row_colors(event):
  99.                 def get_selected():
  100.                     selected_items = []
  101.                     window_y = int(self.geometry().rsplit('+', 1)[-1])
  102.                     tbh = tv.winfo_rooty() - window_y
  103.                     start = dw.winfo_rooty() - tbh - window_y
  104.                     end = dw.winfo_rooty() + dw.winfo_height() - tbh - window_y
  105.    
  106.                     while start < end:
  107.                         start += 1
  108.                         node = tv.identify('item', event.x, start)
  109.                         if not node or node in selected_items:
  110.                             continue
  111.                         selected_items.append(node)
  112.    
  113.                     return sorted(selected_items)
  114.    
  115.                 items = get_selected()
  116.                 self.unbind('<Motion>')
  117.    
  118.                 for item in items:
  119.                     if tv.tag_has('selected', item):
  120.                         if item == self.anchor_item:
  121.                             continue
  122.    
  123.                         tags_add(item, '_selected')
  124.                         if tv.tag_has('selected_odd', item):
  125.                             tag_replace(item, 'selected_odd', 'odd')
  126.                         elif tv.tag_has('selected_even', item):
  127.                             tag_replace(item, 'selected_even', 'even')
  128.                     else:
  129.                         if tv.tag_has('odd', item):
  130.                             tag_replace(item, 'odd', 'selected_odd')
  131.                             tags_add(item, '_selected')
  132.                             self.active_item = item
  133.                         elif tv.tag_has('even', item):
  134.                             tag_replace(item, 'even', 'selected_even')
  135.                             tags_add(item, '_selected')
  136.                             self.active_item = item
  137.    
  138.                 for item in tv.tag_has('_selected'):
  139.                     if item not in items:
  140.                         tags_remove(item, '_selected')
  141.                         if tv.tag_has('odd', item):
  142.                             tag_replace(item, 'odd', 'selected_odd')
  143.                         elif tv.tag_has('even', item):
  144.                             tag_replace(item, 'even', 'selected_even')
  145.                         elif tv.tag_has('selected_odd', item):
  146.                             tag_replace(item, 'selected_odd', 'odd')
  147.                         elif tv.tag_has('selected_even', item):
  148.                             tag_replace(item, 'selected_even', 'even')
  149.    
  150.                 _selected = tv.tag_has('_selected')
  151.    
  152.                 self.bind('<Motion>', selection_window)
  153.    
  154.             def selection_window(event):
  155.                 root_x = self.winfo_rootx()
  156.                 if event.x < self.anchor_x:
  157.                     width = self.anchor_x - event.x
  158.                     coord_x = root_x + event.x
  159.                 else:
  160.                     width = event.x - self.anchor_x
  161.                     coord_x = root_x + self.anchor_x
  162.    
  163.                 if coord_x+width > root_x+self.winfo_width():
  164.                     width -= (coord_x+width)-(root_x+self.winfo_width())
  165.                 elif self.winfo_pointerx() < root_x:
  166.                     width -= (root_x - self.winfo_pointerx())
  167.                     coord_x = root_x
  168.    
  169.                 root_y = self.winfo_rooty()
  170.                 if event.y < self.anchor_y:
  171.                     height = self.anchor_y - event.y
  172.                     coord_y = root_y + event.y
  173.                 else:
  174.                     height = event.y - self.anchor_y
  175.                     coord_y = root_y + self.anchor_y
  176.    
  177.                 if coord_y+height > root_y+self.winfo_height():
  178.                     height -= (coord_y+height)-(root_y+self.winfo_height())
  179.                 elif self.winfo_pointery() < root_y + linespace:
  180.                     height -= (root_y - self.winfo_pointery() + linespace)
  181.                     coord_y = root_y + linespace
  182.                     if height < 0:
  183.                         height = tv.winfo_rooty() + self.anchor_y
  184.    
  185.                 dw.geometry(f'{width}x{height}+{coord_x}+{coord_y}')
  186.                 dw.update_idletasks()
  187.    
  188.                 set_row_colors(event)
  189.    
  190.             self.title('Treeview Demo')
  191.             self.geometry('275x650+2000+100')
  192.             self.rowconfigure(0, weight=1)
  193.             self.columnconfigure(0, weight=1)
  194.    
  195.             f = ttk.Frame(self)
  196.             f.rowconfigure(0, weight=1)
  197.             f.columnconfigure(0, weight=1)
  198.             f.grid(sticky='nsew')
  199.    
  200.             tv = self.tv = ttk.Treeview(f)
  201.             tv.heading('#0', text='Name')
  202.             tv.tag_configure('odd', background='#aaaaaa')
  203.             tv.tag_configure('even', background='#ffffff')
  204.             tv.tag_configure('selected_odd', background='#25a625')
  205.             tv.tag_configure('selected_even', background='#b0eab2')
  206.    
  207.             tag = 'odd'
  208.             for idx in range(0, 4):
  209.                 # Populating the tree with test data.
  210.                 tag = 'even' if tag == 'odd' else 'odd'
  211.                 tv.insert('', idx, f'!{idx}', text=f'Item {idx+1}', open=1, tags=(tag,))
  212.                 tag = 'even' if tag == 'odd' else 'odd'
  213.                 iid = f'!{idx}_!{0}'
  214.                 tv.insert(f'!{idx}', '0', iid, text=f'Menu {idx+1}', open=1, tags=(tag,))
  215.                 for i in range(0, 5):
  216.                     tag = 'even' if tag == 'odd' else 'odd'
  217.                     tv.insert(iid, i, f'{iid}_!{i}', text=f'Sub item {i+1}', tags=(tag,))
  218.    
  219.                 tag = 'even' if tag == 'odd' else 'odd'
  220.                 tv.insert(iid, 5, f'{iid}_!{5}', text=f'Another Menu {idx+1}', open=1, tags=(tag,))
  221.                 iid = f'{iid}_!{5}'
  222.                 for i in range(0, 3):
  223.                     tag = 'even' if tag == 'odd' else 'odd'
  224.                     tv.insert(iid, i, f'{iid}_!{i}', text=f'Sub item {i+1}', tags=(tag,))
  225.    
  226.             tv.config(selectmode="none")
  227.             tv.grid(sticky='NSEW')
  228.    
  229.             dw = tk.Toplevel(self)
  230.             dw.overrideredirect(True)
  231.             dw.wait_visibility(self)
  232.             dw.wm_attributes('-alpha', 0.3)
  233.             dw.wm_attributes("-topmost", True)
  234.             dw.config(bg='#00aaff')
  235.             dw.withdraw()
  236.    
  237.             self.active_item = ''
  238.             font = tkfont.nametofont('TkTextFont')
  239.    
  240.             linespace = font.metrics('linespace') + 5
  241.             style = ttk.Style()
  242.             style.map("Treeview", foreground=fixed_map("foreground"), background=fixed_map("background"))
  243.    
  244.             self.bind('<Escape>', escape)
  245.             self.bind('<Button-1>', button_press)
  246.             self.bind('<ButtonRelease-1>', button_release)
  247.    
  248.    
  249.     def main():
  250.         app = App()
  251.         app.mainloop()
  252.    
  253.    
  254.     if __name__ == '__main__':
  255.         main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement