Advertisement
Uno-Dan

Treeviewx

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