Advertisement
Uno-Dan

Treeview Widget Test

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