Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import tkinter as tk
- import tkinter.ttk as ttk
- import tkinter.font as tkfont
- TITLE_BAR_HEIGHT = 37
- class App(tk.Tk):
- def __init__(self):
- super().__init__()
- self.title('Treeview Demo')
- self.geometry('275x650')
- self.rowconfigure(0, weight=1)
- self.columnconfigure(0, weight=1)
- tv = self.tv = ttk.Treeview(self)
- tv.heading('#0', text='Name')
- tv.tag_configure('odd', background='#aaaaaa')
- tv.tag_configure('even', background='#ffffff')
- tv.tag_configure('selected_odd', background='#25a625')
- tv.tag_configure('selected_even', background='#b0eab2')
- tag = 'odd'
- # Populate tree with test data.
- for idx in range(0, 4):
- tag = 'even' if tag == 'odd' else 'odd'
- tv.insert('', idx, f'!{idx}', text=f'Item {idx+1}', open=1, tags=(tag,))
- tag = 'even' if tag == 'odd' else 'odd'
- iid = f'!{idx}_!{0}'
- tv.insert(f'!{idx}', '0', iid, text=f'Menu {idx+1}', open=1, tags=(tag,))
- for i in range(0, 5):
- tag = 'even' if tag == 'odd' else 'odd'
- tv.insert(iid, i, f'{iid}_!{i}', text=f'Sub item {i+1}', tags=(tag,))
- tag = 'even' if tag == 'odd' else 'odd'
- tv.insert(iid, 5, f'{iid}_!{5}', text=f'Another Menu {idx+1}', open=1, tags=(tag,))
- iid = f'{iid}_!{5}'
- for i in range(0, 3):
- tag = 'even' if tag == 'odd' else 'odd'
- tv.insert(iid, i, f'{iid}_!{i}', text=f'Sub item {i+1}', tags=(tag,))
- tv.config(selectmode="none")
- tv.grid(sticky='NSEW')
- dw = tk.Toplevel()
- dw.overrideredirect(True)
- dw.wait_visibility(self)
- dw.wm_attributes('-alpha', 0.2)
- dw.wm_attributes("-topmost", True)
- dw.config(bg='#00aaff')
- dw.withdraw()
- self.active_item = ''
- font = tkfont.nametofont('TkTextFont')
- linespace = font.metrics('linespace') + 5
- def set_row_colors(event):
- def get_selected():
- self.unbind('<Motion>')
- pos_y = int(self.geometry().rsplit('+', 1)[-1])
- current_y = dw.winfo_rooty() - TITLE_BAR_HEIGHT - pos_y
- end = dw.winfo_rooty() + dw.winfo_height() - TITLE_BAR_HEIGHT - pos_y
- _root = tv.identify('item', event.x, event.y)
- _selected = []
- if current_y < end:
- while current_y < end:
- current_y += 1
- _item = tv.identify('item', event.x, current_y)
- if not _item or _item in _selected:
- continue
- _selected.append(_item)
- if _root not in _selected and _root:
- _selected.append(_root)
- self.bind('<Motion>', selection_window)
- return sorted(_selected)
- item = tv.identify('item', event.x, event.y)
- if item == self.active_item:
- return
- selected = get_selected()
- for item in selected:
- if not tv.tag_has('selected', item):
- if tv.tag_has('odd', item):
- tag_replace(item, 'odd', 'selected_odd')
- tags_add(item, '_selected')
- self.active_item = item
- elif tv.tag_has('even', item):
- tag_replace(item, 'even', 'selected_even')
- tags_add(item, '_selected')
- self.active_item = item
- else:
- if item == self.anchor_item:
- continue
- if tv.tag_has('selected_odd', item):
- tag_replace(item, 'selected_odd', 'odd')
- tags_add(item, '_selected')
- elif tv.tag_has('selected_even', item):
- tag_replace(item, 'selected_even', 'even')
- tags_add(item, '_selected')
- for item in tv.tag_has('_selected'):
- if item not in selected:
- tags_remove(item, '_selected')
- if tv.tag_has('odd', item):
- tag_replace(item, 'odd', 'selected_odd')
- elif tv.tag_has('even', item):
- tag_replace(item, 'even', 'selected_even')
- elif tv.tag_has('selected_odd', item):
- tag_replace(item, 'selected_odd', 'odd')
- elif tv.tag_has('selected_even', item):
- tag_replace(item, 'selected_even', 'even')
- def tag_replace(item, old, new):
- tags_remove(item, old)
- tags_add(item, new)
- def tags_add(item, tags):
- if isinstance(tags, str):
- tags = (tags,)
- _tags = list(tv.item(item)['tags'])
- _tags = [] if not _tags else _tags
- for _tag in tags:
- if _tag not in _tags:
- _tags.append(_tag)
- tv.item(item, tags=_tags)
- def tags_remove(item, tags):
- if isinstance(tags, str):
- tags = (tags,)
- _tags = list(tv.item(item)['tags'])
- for _tag in tags:
- if _tag in _tags:
- _tags.pop(_tags.index(_tag))
- tv.item(item, tags=_tags)
- def tags_remove_all(*tags):
- def do_remove(node):
- tags_remove(node, tags)
- for node in tv.get_children(node):
- do_remove(node)
- for child in tv.get_children():
- do_remove(child)
- def tags_refresh(event):
- for item in tv.tag_has('selected_odd'):
- tags_add(item, 'odd')
- tags_remove(item, 'selected_odd')
- for item in tv.tag_has('selected_even'):
- tags_add(item, 'even')
- tags_remove(item, 'selected_even')
- def escape(event):
- tags_remove_all('selected', '_selected')
- tags_refresh(event)
- def button_press(event):
- self.selected = []
- self.anchor_x, self.anchor_y = event.x, event.y
- item = self.anchor_item = self.active_item = tv.identify('item', event.x, event.y)
- if not item:
- return
- if event.state == 20:
- tags_add(item, 'selected')
- if tv.tag_has('odd', item):
- tag_replace(item, 'odd', 'selected_odd')
- elif tv.tag_has('selected_odd', item):
- tag_replace(item, 'selected_odd', 'odd')
- elif tv.tag_has('even', item):
- tag_replace(item, 'even', 'selected_even')
- elif tv.tag_has('selected_even', item):
- tag_replace(item, 'selected_even', 'even')
- else:
- tags_remove_all('selected', '_selected')
- tags_refresh(event)
- tags_add(item, 'selected')
- if tv.tag_has('odd', item):
- tag_replace(item, 'odd', 'selected_odd')
- elif tv.tag_has('even', item):
- tag_replace(item, 'even', 'selected_even')
- dw.geometry('0x0+0+0')
- dw.deiconify()
- self.bind('<Motion>', selection_window)
- def button_release(event):
- dw.withdraw()
- self.unbind('<Motion>')
- for item in tv.tag_has('_selected'):
- tags_add(item, ('selected', ))
- tags_add(tv.identify('item', event.x, event.y), ('selected', ))
- tags_remove_all('_selected')
- def selection_window(event):
- root_x = self.winfo_rootx()
- if event.x < self.anchor_x:
- width = self.anchor_x - event.x
- coord_x = root_x + event.x
- else:
- width = event.x - self.anchor_x
- coord_x = root_x + self.anchor_x
- if coord_x+width > root_x+self.winfo_width():
- width -= (coord_x+width)-(root_x+self.winfo_width())
- elif self.winfo_pointerx() < root_x:
- width -= (root_x - self.winfo_pointerx())
- coord_x = root_x
- root_y = self.winfo_rooty()
- if event.y < self.anchor_y:
- height = self.anchor_y - event.y
- coord_y = root_y + event.y
- else:
- height = event.y - self.anchor_y
- coord_y = root_y + self.anchor_y
- if coord_y+height > root_y+self.winfo_height():
- height -= (coord_y+height)-(root_y+self.winfo_height())
- elif self.winfo_pointery() < root_y + linespace:
- height -= (root_y - self.winfo_pointery() + linespace)
- coord_y = root_y + linespace
- if height < 0:
- height = tv.winfo_rooty() + self.anchor_y
- dw.geometry(f'{width}x{height}+{coord_x}+{coord_y}')
- dw.update_idletasks()
- set_row_colors(event)
- self.update_idletasks()
- self.bind('<Escape>', escape)
- self.bind('<Button-1>', button_press)
- self.bind('<ButtonRelease-1>', button_release)
- def main():
- app = App()
- app.mainloop()
- if __name__ == '__main__':
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement