Advertisement
Uno-Dan

Treeview Shows How To Get Selected.

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